aboutsummaryrefslogtreecommitdiffstats
path: root/components/style/stylesheets
diff options
context:
space:
mode:
authorDelan Azabani <dazabani@igalia.com>2024-02-27 23:39:06 +0800
committerGitHub <noreply@github.com>2024-02-27 15:39:06 +0000
commitfaf754dfa655f0b9a28f62bc47a78fbf78ebcaf4 (patch)
tree4725e1446680d036797b1fc258733ae6b2c9f354 /components/style/stylesheets
parentb07505417e629bbb081be9683630f2d7a5f50544 (diff)
downloadservo-faf754dfa655f0b9a28f62bc47a78fbf78ebcaf4.tar.gz
servo-faf754dfa655f0b9a28f62bc47a78fbf78ebcaf4.zip
Move Stylo to its own repo (#31350)
* Remove packages that were moved to external repo * Add workspace dependencies pointing to 2023-06-14 branch * Fix servo-tidy.toml errors * Update commit to include #31346 * Update commit to include servo/stylo#2 * Move css-properties.json lookup to target/doc/stylo * Remove dependency on vendored mako in favour of pypi dependency This also removes etc/ci/generate_workflow.py, which has been unused since at least 9e71bd6a7010d6e5723831696ae0ebe26b47682f. * Add temporary code to debug Windows test failures * Fix failures on Windows due to custom target dir * Update commit to include servo/stylo#3 * Fix license in tests/unit/style/build.rs * Document how to build with local Stylo in Cargo.toml
Diffstat (limited to 'components/style/stylesheets')
-rw-r--r--components/style/stylesheets/container_rule.rs632
-rw-r--r--components/style/stylesheets/counter_style_rule.rs7
-rw-r--r--components/style/stylesheets/document_rule.rs305
-rw-r--r--components/style/stylesheets/font_face_rule.rs7
-rw-r--r--components/style/stylesheets/font_feature_values_rule.rs490
-rw-r--r--components/style/stylesheets/font_palette_values_rule.rs268
-rw-r--r--components/style/stylesheets/import_rule.rs332
-rw-r--r--components/style/stylesheets/keyframes_rule.rs691
-rw-r--r--components/style/stylesheets/layer_rule.rs228
-rw-r--r--components/style/stylesheets/loader.rs31
-rw-r--r--components/style/stylesheets/media_rule.rs71
-rw-r--r--components/style/stylesheets/mod.rs582
-rw-r--r--components/style/stylesheets/namespace_rule.rs43
-rw-r--r--components/style/stylesheets/origin.rs247
-rw-r--r--components/style/stylesheets/page_rule.rs145
-rw-r--r--components/style/stylesheets/property_rule.rs5
-rw-r--r--components/style/stylesheets/rule_list.rs198
-rw-r--r--components/style/stylesheets/rule_parser.rs867
-rw-r--r--components/style/stylesheets/rules_iterator.rs326
-rw-r--r--components/style/stylesheets/style_rule.rs104
-rw-r--r--components/style/stylesheets/stylesheet.rs605
-rw-r--r--components/style/stylesheets/supports_rule.rs448
22 files changed, 0 insertions, 6632 deletions
diff --git a/components/style/stylesheets/container_rule.rs b/components/style/stylesheets/container_rule.rs
deleted file mode 100644
index f9d488b9b49..00000000000
--- a/components/style/stylesheets/container_rule.rs
+++ /dev/null
@@ -1,632 +0,0 @@
-/* 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/. */
-
-//! A [`@container`][container] rule.
-//!
-//! [container]: https://drafts.csswg.org/css-contain-3/#container-rule
-
-use crate::computed_value_flags::ComputedValueFlags;
-use crate::dom::TElement;
-use crate::logical_geometry::{LogicalSize, WritingMode};
-use crate::media_queries::Device;
-use crate::parser::ParserContext;
-use crate::properties::ComputedValues;
-use crate::queries::condition::KleeneValue;
-use crate::queries::feature::{AllowsRanges, Evaluator, FeatureFlags, QueryFeatureDescription};
-use crate::queries::values::Orientation;
-use crate::queries::{FeatureType, QueryCondition};
-use crate::shared_lock::{
- DeepCloneParams, DeepCloneWithLock, Locked, SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard,
-};
-use crate::str::CssStringWriter;
-use crate::stylesheets::CssRules;
-use crate::values::computed::{CSSPixelLength, ContainerType, Context, Ratio};
-use crate::values::specified::ContainerName;
-use app_units::Au;
-use cssparser::{Parser, SourceLocation};
-use euclid::default::Size2D;
-#[cfg(feature = "gecko")]
-use malloc_size_of::{MallocSizeOfOps, MallocUnconditionalShallowSizeOf};
-use servo_arc::Arc;
-use std::fmt::{self, Write};
-use style_traits::{CssWriter, ParseError, ToCss};
-
-/// A container rule.
-#[derive(Debug, ToShmem)]
-pub struct ContainerRule {
- /// The container query and name.
- pub condition: Arc<ContainerCondition>,
- /// The nested rules inside the block.
- pub rules: Arc<Locked<CssRules>>,
- /// The source position where this rule was found.
- pub source_location: SourceLocation,
-}
-
-impl ContainerRule {
- /// Returns the query condition.
- pub fn query_condition(&self) -> &QueryCondition {
- &self.condition.condition
- }
-
- /// Returns the query name filter.
- pub fn container_name(&self) -> &ContainerName {
- &self.condition.name
- }
-
- /// Measure heap usage.
- #[cfg(feature = "gecko")]
- pub fn size_of(&self, guard: &SharedRwLockReadGuard, ops: &mut MallocSizeOfOps) -> usize {
- // Measurement of other fields may be added later.
- self.rules.unconditional_shallow_size_of(ops) +
- self.rules.read_with(guard).size_of(guard, ops)
- }
-}
-
-impl DeepCloneWithLock for ContainerRule {
- fn deep_clone_with_lock(
- &self,
- lock: &SharedRwLock,
- guard: &SharedRwLockReadGuard,
- params: &DeepCloneParams,
- ) -> Self {
- let rules = self.rules.read_with(guard);
- Self {
- condition: self.condition.clone(),
- rules: Arc::new(lock.wrap(rules.deep_clone_with_lock(lock, guard, params))),
- source_location: self.source_location.clone(),
- }
- }
-}
-
-impl ToCssWithGuard for ContainerRule {
- fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
- dest.write_str("@container ")?;
- {
- let mut writer = CssWriter::new(dest);
- if !self.condition.name.is_none() {
- self.condition.name.to_css(&mut writer)?;
- writer.write_char(' ')?;
- }
- self.condition.condition.to_css(&mut writer)?;
- }
- self.rules.read_with(guard).to_css_block(guard, dest)
- }
-}
-
-/// A container condition and filter, combined.
-#[derive(Debug, ToShmem, ToCss)]
-pub struct ContainerCondition {
- #[css(skip_if = "ContainerName::is_none")]
- name: ContainerName,
- condition: QueryCondition,
- #[css(skip)]
- flags: FeatureFlags,
-}
-
-/// The result of a successful container query lookup.
-pub struct ContainerLookupResult<E> {
- /// The relevant container.
- pub element: E,
- /// The sizing / writing-mode information of the container.
- pub info: ContainerInfo,
- /// The style of the element.
- pub style: Arc<ComputedValues>,
-}
-
-fn container_type_axes(ty_: ContainerType, wm: WritingMode) -> FeatureFlags {
- match ty_ {
- ContainerType::Size => FeatureFlags::all_container_axes(),
- ContainerType::InlineSize => {
- let physical_axis = if wm.is_vertical() {
- FeatureFlags::CONTAINER_REQUIRES_HEIGHT_AXIS
- } else {
- FeatureFlags::CONTAINER_REQUIRES_WIDTH_AXIS
- };
- FeatureFlags::CONTAINER_REQUIRES_INLINE_AXIS | physical_axis
- },
- ContainerType::Normal => FeatureFlags::empty(),
- }
-}
-
-enum TraversalResult<T> {
- InProgress,
- StopTraversal,
- Done(T),
-}
-
-fn traverse_container<E, F, R>(
- mut e: E,
- originating_element_style: Option<&ComputedValues>,
- evaluator: F,
-) -> Option<(E, R)>
-where
- E: TElement,
- F: Fn(E, Option<&ComputedValues>) -> TraversalResult<R>,
-{
- if originating_element_style.is_some() {
- match evaluator(e, originating_element_style) {
- TraversalResult::InProgress => {},
- TraversalResult::StopTraversal => return None,
- TraversalResult::Done(result) => return Some((e, result)),
- }
- }
- while let Some(element) = e.traversal_parent() {
- match evaluator(element, None) {
- TraversalResult::InProgress => {},
- TraversalResult::StopTraversal => return None,
- TraversalResult::Done(result) => return Some((element, result)),
- }
- e = element;
- }
-
- None
-}
-
-impl ContainerCondition {
- /// Parse a container condition.
- pub fn parse<'a>(
- context: &ParserContext,
- input: &mut Parser<'a, '_>,
- ) -> Result<Self, ParseError<'a>> {
- let name = input
- .try_parse(|input| ContainerName::parse_for_query(context, input))
- .ok()
- .unwrap_or_else(ContainerName::none);
- let condition = QueryCondition::parse(context, input, FeatureType::Container)?;
- let flags = condition.cumulative_flags();
- Ok(Self {
- name,
- condition,
- flags,
- })
- }
-
- fn valid_container_info<E>(
- &self,
- potential_container: E,
- originating_element_style: Option<&ComputedValues>,
- ) -> TraversalResult<ContainerLookupResult<E>>
- where
- E: TElement,
- {
- let data;
- let style = match originating_element_style {
- Some(s) => s,
- None => {
- data = match potential_container.borrow_data() {
- Some(d) => d,
- None => return TraversalResult::InProgress,
- };
- &**data.styles.primary()
- },
- };
- let wm = style.writing_mode;
- let box_style = style.get_box();
-
- // Filter by container-type.
- let container_type = box_style.clone_container_type();
- let available_axes = container_type_axes(container_type, wm);
- if !available_axes.contains(self.flags.container_axes()) {
- return TraversalResult::InProgress;
- }
-
- // Filter by container-name.
- let container_name = box_style.clone_container_name();
- for filter_name in self.name.0.iter() {
- if !container_name.0.contains(filter_name) {
- return TraversalResult::InProgress;
- }
- }
-
- let size = potential_container.query_container_size(&box_style.clone_display());
- let style = style.to_arc();
- TraversalResult::Done(ContainerLookupResult {
- element: potential_container,
- info: ContainerInfo { size, wm },
- style,
- })
- }
-
- /// Performs container lookup for a given element.
- pub fn find_container<E>(
- &self,
- e: E,
- originating_element_style: Option<&ComputedValues>,
- ) -> Option<ContainerLookupResult<E>>
- where
- E: TElement,
- {
- match traverse_container(
- e,
- originating_element_style,
- |element, originating_element_style| {
- self.valid_container_info(element, originating_element_style)
- },
- ) {
- Some((_, result)) => Some(result),
- None => None,
- }
- }
-
- /// Tries to match a container query condition for a given element.
- pub(crate) fn matches<E>(
- &self,
- device: &Device,
- element: E,
- originating_element_style: Option<&ComputedValues>,
- invalidation_flags: &mut ComputedValueFlags,
- ) -> KleeneValue
- where
- E: TElement,
- {
- let result = self.find_container(element, originating_element_style);
- let (container, info) = match result {
- Some(r) => (Some(r.element), Some((r.info, r.style))),
- None => (None, None),
- };
- // Set up the lookup for the container in question, as the condition may be using container query lengths.
- let size_query_container_lookup = ContainerSizeQuery::for_option_element(container, None);
- Context::for_container_query_evaluation(
- device,
- info,
- size_query_container_lookup,
- |context| {
- let matches = self.condition.matches(context);
- if context
- .style()
- .flags()
- .contains(ComputedValueFlags::USES_VIEWPORT_UNITS)
- {
- // TODO(emilio): Might need something similar to improve
- // invalidation of font relative container-query lengths.
- invalidation_flags
- .insert(ComputedValueFlags::USES_VIEWPORT_UNITS_ON_CONTAINER_QUERIES);
- }
- matches
- },
- )
- }
-}
-
-/// Information needed to evaluate an individual container query.
-#[derive(Copy, Clone)]
-pub struct ContainerInfo {
- size: Size2D<Option<Au>>,
- wm: WritingMode,
-}
-
-impl ContainerInfo {
- fn size(&self) -> Option<Size2D<Au>> {
- Some(Size2D::new(self.size.width?, self.size.height?))
- }
-}
-
-fn eval_width(context: &Context) -> Option<CSSPixelLength> {
- let info = context.container_info.as_ref()?;
- Some(CSSPixelLength::new(info.size.width?.to_f32_px()))
-}
-
-fn eval_height(context: &Context) -> Option<CSSPixelLength> {
- let info = context.container_info.as_ref()?;
- Some(CSSPixelLength::new(info.size.height?.to_f32_px()))
-}
-
-fn eval_inline_size(context: &Context) -> Option<CSSPixelLength> {
- let info = context.container_info.as_ref()?;
- Some(CSSPixelLength::new(
- LogicalSize::from_physical(info.wm, info.size)
- .inline?
- .to_f32_px(),
- ))
-}
-
-fn eval_block_size(context: &Context) -> Option<CSSPixelLength> {
- let info = context.container_info.as_ref()?;
- Some(CSSPixelLength::new(
- LogicalSize::from_physical(info.wm, info.size)
- .block?
- .to_f32_px(),
- ))
-}
-
-fn eval_aspect_ratio(context: &Context) -> Option<Ratio> {
- let info = context.container_info.as_ref()?;
- Some(Ratio::new(
- info.size.width?.0 as f32,
- info.size.height?.0 as f32,
- ))
-}
-
-fn eval_orientation(context: &Context, value: Option<Orientation>) -> KleeneValue {
- let size = match context.container_info.as_ref().and_then(|info| info.size()) {
- Some(size) => size,
- None => return KleeneValue::Unknown,
- };
- KleeneValue::from(Orientation::eval(size, value))
-}
-
-/// https://drafts.csswg.org/css-contain-3/#container-features
-///
-/// TODO: Support style queries, perhaps.
-pub static CONTAINER_FEATURES: [QueryFeatureDescription; 6] = [
- feature!(
- atom!("width"),
- AllowsRanges::Yes,
- Evaluator::OptionalLength(eval_width),
- FeatureFlags::CONTAINER_REQUIRES_WIDTH_AXIS,
- ),
- feature!(
- atom!("height"),
- AllowsRanges::Yes,
- Evaluator::OptionalLength(eval_height),
- FeatureFlags::CONTAINER_REQUIRES_HEIGHT_AXIS,
- ),
- feature!(
- atom!("inline-size"),
- AllowsRanges::Yes,
- Evaluator::OptionalLength(eval_inline_size),
- FeatureFlags::CONTAINER_REQUIRES_INLINE_AXIS,
- ),
- feature!(
- atom!("block-size"),
- AllowsRanges::Yes,
- Evaluator::OptionalLength(eval_block_size),
- FeatureFlags::CONTAINER_REQUIRES_BLOCK_AXIS,
- ),
- feature!(
- atom!("aspect-ratio"),
- AllowsRanges::Yes,
- Evaluator::OptionalNumberRatio(eval_aspect_ratio),
- // XXX from_bits_truncate is const, but the pipe operator isn't, so this
- // works around it.
- FeatureFlags::from_bits_truncate(
- FeatureFlags::CONTAINER_REQUIRES_BLOCK_AXIS.bits() |
- FeatureFlags::CONTAINER_REQUIRES_INLINE_AXIS.bits()
- ),
- ),
- feature!(
- atom!("orientation"),
- AllowsRanges::No,
- keyword_evaluator!(eval_orientation, Orientation),
- FeatureFlags::from_bits_truncate(
- FeatureFlags::CONTAINER_REQUIRES_BLOCK_AXIS.bits() |
- FeatureFlags::CONTAINER_REQUIRES_INLINE_AXIS.bits()
- ),
- ),
-];
-
-/// Result of a container size query, signifying the hypothetical containment boundary in terms of physical axes.
-/// Defined by up to two size containers. Queries on logical axes are resolved with respect to the querying
-/// element's writing mode.
-#[derive(Copy, Clone, Default)]
-pub struct ContainerSizeQueryResult {
- width: Option<Au>,
- height: Option<Au>,
-}
-
-impl ContainerSizeQueryResult {
- fn get_viewport_size(context: &Context) -> Size2D<Au> {
- use crate::values::specified::ViewportVariant;
- context.viewport_size_for_viewport_unit_resolution(ViewportVariant::Small)
- }
-
- fn get_logical_viewport_size(context: &Context) -> LogicalSize<Au> {
- LogicalSize::from_physical(
- context.builder.writing_mode,
- Self::get_viewport_size(context),
- )
- }
-
- /// Get the inline-size of the query container.
- pub fn get_container_inline_size(&self, context: &Context) -> Au {
- if context.builder.writing_mode.is_horizontal() {
- if let Some(w) = self.width {
- return w;
- }
- } else {
- if let Some(h) = self.height {
- return h;
- }
- }
- Self::get_logical_viewport_size(context).inline
- }
-
- /// Get the block-size of the query container.
- pub fn get_container_block_size(&self, context: &Context) -> Au {
- if context.builder.writing_mode.is_horizontal() {
- self.get_container_height(context)
- } else {
- self.get_container_width(context)
- }
- }
-
- /// Get the width of the query container.
- pub fn get_container_width(&self, context: &Context) -> Au {
- if let Some(w) = self.width {
- return w;
- }
- Self::get_viewport_size(context).width
- }
-
- /// Get the height of the query container.
- pub fn get_container_height(&self, context: &Context) -> Au {
- if let Some(h) = self.height {
- return h;
- }
- Self::get_viewport_size(context).height
- }
-
- // Merge the result of a subsequent lookup, preferring the initial result.
- fn merge(self, new_result: Self) -> Self {
- let mut result = self;
- if let Some(width) = new_result.width {
- result.width.get_or_insert(width);
- }
- if let Some(height) = new_result.height {
- result.height.get_or_insert(height);
- }
- result
- }
-
- fn is_complete(&self) -> bool {
- self.width.is_some() && self.height.is_some()
- }
-}
-
-/// Unevaluated lazy container size query.
-pub enum ContainerSizeQuery<'a> {
- /// Query prior to evaluation.
- NotEvaluated(Box<dyn Fn() -> ContainerSizeQueryResult + 'a>),
- /// Cached evaluated result.
- Evaluated(ContainerSizeQueryResult),
-}
-
-impl<'a> ContainerSizeQuery<'a> {
- fn evaluate_potential_size_container<E>(
- e: E,
- originating_element_style: Option<&ComputedValues>,
- ) -> TraversalResult<ContainerSizeQueryResult>
- where
- E: TElement,
- {
- let data;
- let style = match originating_element_style {
- Some(s) => s,
- None => {
- data = match e.borrow_data() {
- Some(d) => d,
- None => return TraversalResult::InProgress,
- };
- &**data.styles.primary()
- },
- };
- if !style
- .flags
- .contains(ComputedValueFlags::SELF_OR_ANCESTOR_HAS_SIZE_CONTAINER_TYPE)
- {
- // We know we won't find a size container.
- return TraversalResult::StopTraversal;
- }
-
- let wm = style.writing_mode;
- let box_style = style.get_box();
-
- let container_type = box_style.clone_container_type();
- let size = e.query_container_size(&box_style.clone_display());
- match container_type {
- ContainerType::Size => TraversalResult::Done(ContainerSizeQueryResult {
- width: size.width,
- height: size.height,
- }),
- ContainerType::InlineSize => {
- if wm.is_horizontal() {
- TraversalResult::Done(ContainerSizeQueryResult {
- width: size.width,
- height: None,
- })
- } else {
- TraversalResult::Done(ContainerSizeQueryResult {
- width: None,
- height: size.height,
- })
- }
- },
- ContainerType::Normal => TraversalResult::InProgress,
- }
- }
-
- /// Find the query container size for a given element. Meant to be used as a callback for new().
- fn lookup<E>(
- element: E,
- originating_element_style: Option<&ComputedValues>,
- ) -> ContainerSizeQueryResult
- where
- E: TElement + 'a,
- {
- match traverse_container(
- element,
- originating_element_style,
- |e, originating_element_style| {
- Self::evaluate_potential_size_container(e, originating_element_style)
- },
- ) {
- Some((container, result)) => {
- if result.is_complete() {
- result
- } else {
- // Traverse up from the found size container to see if we can get a complete containment.
- result.merge(Self::lookup(container, None))
- }
- },
- None => ContainerSizeQueryResult::default(),
- }
- }
-
- /// Create a new instance of the container size query for given element, with a deferred lookup callback.
- pub fn for_element<E>(element: E, originating_element_style: Option<&'a ComputedValues>) -> Self
- where
- E: TElement + 'a,
- {
- let parent;
- let data;
- let style = match originating_element_style {
- Some(s) => Some(s),
- None => {
- // No need to bother if we're the top element.
- parent = match element.traversal_parent() {
- Some(parent) => parent,
- None => return Self::none(),
- };
- data = parent.borrow_data();
- data.as_ref().map(|data| &**data.styles.primary())
- },
- };
- let should_traverse = match style {
- Some(style) => style
- .flags
- .contains(ComputedValueFlags::SELF_OR_ANCESTOR_HAS_SIZE_CONTAINER_TYPE),
- None => true, // `display: none`, still want to show a correct computed value, so give it a try.
- };
- if should_traverse {
- return Self::NotEvaluated(Box::new(move || {
- Self::lookup(element, originating_element_style)
- }));
- }
- Self::none()
- }
-
- /// Create a new instance, but with optional element.
- pub fn for_option_element<E>(
- element: Option<E>,
- originating_element_style: Option<&'a ComputedValues>,
- ) -> Self
- where
- E: TElement + 'a,
- {
- if let Some(e) = element {
- Self::for_element(e, originating_element_style)
- } else {
- Self::none()
- }
- }
-
- /// Create a query that evaluates to empty, for cases where container size query is not required.
- pub fn none() -> Self {
- ContainerSizeQuery::Evaluated(ContainerSizeQueryResult::default())
- }
-
- /// Get the result of the container size query, doing the lookup if called for the first time.
- pub fn get(&mut self) -> ContainerSizeQueryResult {
- match self {
- Self::NotEvaluated(lookup) => {
- *self = Self::Evaluated((lookup)());
- match self {
- Self::Evaluated(info) => *info,
- _ => unreachable!("Just evaluated but not set?"),
- }
- },
- Self::Evaluated(info) => *info,
- }
- }
-}
diff --git a/components/style/stylesheets/counter_style_rule.rs b/components/style/stylesheets/counter_style_rule.rs
deleted file mode 100644
index 974b76b8060..00000000000
--- a/components/style/stylesheets/counter_style_rule.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-/* 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/. */
-
-#![allow(missing_docs)]
-
-pub use crate::counter_style::CounterStyleRuleData as CounterStyleRule;
diff --git a/components/style/stylesheets/document_rule.rs b/components/style/stylesheets/document_rule.rs
deleted file mode 100644
index 75edab308db..00000000000
--- a/components/style/stylesheets/document_rule.rs
+++ /dev/null
@@ -1,305 +0,0 @@
-/* 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/. */
-
-//! [@document rules](https://www.w3.org/TR/2012/WD-css3-conditional-20120911/#at-document)
-//! initially in CSS Conditional Rules Module Level 3, @document has been postponed to the level 4.
-//! We implement the prefixed `@-moz-document`.
-
-use crate::media_queries::Device;
-use crate::parser::{Parse, ParserContext};
-use crate::shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked};
-use crate::shared_lock::{SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard};
-use crate::str::CssStringWriter;
-use crate::stylesheets::CssRules;
-use crate::values::CssUrl;
-use cssparser::{BasicParseErrorKind, Parser, SourceLocation};
-#[cfg(feature = "gecko")]
-use malloc_size_of::{MallocSizeOfOps, MallocUnconditionalShallowSizeOf};
-use servo_arc::Arc;
-use std::fmt::{self, Write};
-use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
-
-#[derive(Debug, ToShmem)]
-/// A @-moz-document rule
-pub struct DocumentRule {
- /// The parsed condition
- pub condition: DocumentCondition,
- /// Child rules
- pub rules: Arc<Locked<CssRules>>,
- /// The line and column of the rule's source code.
- pub source_location: SourceLocation,
-}
-
-impl DocumentRule {
- /// Measure heap usage.
- #[cfg(feature = "gecko")]
- pub fn size_of(&self, guard: &SharedRwLockReadGuard, ops: &mut MallocSizeOfOps) -> usize {
- // Measurement of other fields may be added later.
- self.rules.unconditional_shallow_size_of(ops) +
- self.rules.read_with(guard).size_of(guard, ops)
- }
-}
-
-impl ToCssWithGuard for DocumentRule {
- fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
- dest.write_str("@-moz-document ")?;
- self.condition.to_css(&mut CssWriter::new(dest))?;
- dest.write_str(" {")?;
- for rule in self.rules.read_with(guard).0.iter() {
- dest.write_char(' ')?;
- rule.to_css(guard, dest)?;
- }
- dest.write_str(" }")
- }
-}
-
-impl DeepCloneWithLock for DocumentRule {
- /// Deep clones this DocumentRule.
- fn deep_clone_with_lock(
- &self,
- lock: &SharedRwLock,
- guard: &SharedRwLockReadGuard,
- params: &DeepCloneParams,
- ) -> Self {
- let rules = self.rules.read_with(guard);
- DocumentRule {
- condition: self.condition.clone(),
- rules: Arc::new(lock.wrap(rules.deep_clone_with_lock(lock, guard, params))),
- source_location: self.source_location.clone(),
- }
- }
-}
-
-/// The kind of media document that the rule will match.
-#[derive(Clone, Copy, Debug, Parse, PartialEq, ToCss, ToShmem)]
-#[allow(missing_docs)]
-pub enum MediaDocumentKind {
- All,
- Plugin,
- Image,
- Video,
-}
-
-/// A matching function for a `@document` rule's condition.
-#[derive(Clone, Debug, ToCss, ToShmem)]
-pub enum DocumentMatchingFunction {
- /// Exact URL matching function. It evaluates to true whenever the
- /// URL of the document being styled is exactly the URL given.
- Url(CssUrl),
- /// URL prefix matching function. It evaluates to true whenever the
- /// URL of the document being styled has the argument to the
- /// function as an initial substring (which is true when the two
- /// strings are equal). When the argument is the empty string,
- /// it evaluates to true for all documents.
- #[css(function)]
- UrlPrefix(String),
- /// Domain matching function. It evaluates to true whenever the URL
- /// of the document being styled has a host subcomponent and that
- /// host subcomponent is exactly the argument to the ‘domain()’
- /// function or a final substring of the host component is a
- /// period (U+002E) immediately followed by the argument to the
- /// ‘domain()’ function.
- #[css(function)]
- Domain(String),
- /// Regular expression matching function. It evaluates to true
- /// whenever the regular expression matches the entirety of the URL
- /// of the document being styled.
- #[css(function)]
- Regexp(String),
- /// Matching function for a media document.
- #[css(function)]
- MediaDocument(MediaDocumentKind),
- /// Matching function for a plain-text document.
- #[css(function)]
- PlainTextDocument(()),
- /// Matching function for a document that can be observed by other content
- /// documents.
- #[css(function)]
- UnobservableDocument(()),
-}
-
-macro_rules! parse_quoted_or_unquoted_string {
- ($input:ident, $url_matching_function:expr) => {
- $input.parse_nested_block(|input| {
- let start = input.position();
- input
- .parse_entirely(|input| {
- let string = input.expect_string()?;
- Ok($url_matching_function(string.as_ref().to_owned()))
- })
- .or_else(|_: ParseError| {
- while let Ok(_) = input.next() {}
- Ok($url_matching_function(input.slice_from(start).to_string()))
- })
- })
- };
-}
-
-impl DocumentMatchingFunction {
- /// Parse a URL matching function for a`@document` rule's condition.
- pub fn parse<'i, 't>(
- context: &ParserContext,
- input: &mut Parser<'i, 't>,
- ) -> Result<Self, ParseError<'i>> {
- if let Ok(url) = input.try_parse(|input| CssUrl::parse(context, input)) {
- return Ok(DocumentMatchingFunction::Url(url));
- }
-
- let location = input.current_source_location();
- let function = input.expect_function()?.clone();
- match_ignore_ascii_case! { &function,
- "url-prefix" => {
- parse_quoted_or_unquoted_string!(input, DocumentMatchingFunction::UrlPrefix)
- },
- "domain" => {
- parse_quoted_or_unquoted_string!(input, DocumentMatchingFunction::Domain)
- },
- "regexp" => {
- input.parse_nested_block(|input| {
- Ok(DocumentMatchingFunction::Regexp(
- input.expect_string()?.as_ref().to_owned(),
- ))
- })
- },
- "media-document" => {
- input.parse_nested_block(|input| {
- let kind = MediaDocumentKind::parse(input)?;
- Ok(DocumentMatchingFunction::MediaDocument(kind))
- })
- },
-
- "plain-text-document" => {
- input.parse_nested_block(|input| {
- input.expect_exhausted()?;
- Ok(DocumentMatchingFunction::PlainTextDocument(()))
- })
- },
-
- "unobservable-document" => {
- input.parse_nested_block(|input| {
- input.expect_exhausted()?;
- Ok(DocumentMatchingFunction::UnobservableDocument(()))
- })
- },
-
- _ => {
- Err(location.new_custom_error(
- StyleParseErrorKind::UnexpectedFunction(function.clone())
- ))
- },
- }
- }
-
- #[cfg(feature = "gecko")]
- /// Evaluate a URL matching function.
- pub fn evaluate(&self, device: &Device) -> bool {
- use crate::gecko_bindings::bindings::Gecko_DocumentRule_UseForPresentation;
- use crate::gecko_bindings::structs::DocumentMatchingFunction as GeckoDocumentMatchingFunction;
- use nsstring::nsCStr;
-
- let func = match *self {
- DocumentMatchingFunction::Url(_) => GeckoDocumentMatchingFunction::URL,
- DocumentMatchingFunction::UrlPrefix(_) => GeckoDocumentMatchingFunction::URLPrefix,
- DocumentMatchingFunction::Domain(_) => GeckoDocumentMatchingFunction::Domain,
- DocumentMatchingFunction::Regexp(_) => GeckoDocumentMatchingFunction::RegExp,
- DocumentMatchingFunction::MediaDocument(_) => {
- GeckoDocumentMatchingFunction::MediaDocument
- },
- DocumentMatchingFunction::PlainTextDocument(..) => {
- GeckoDocumentMatchingFunction::PlainTextDocument
- },
- DocumentMatchingFunction::UnobservableDocument(..) => {
- GeckoDocumentMatchingFunction::UnobservableDocument
- },
- };
-
- let pattern = nsCStr::from(match *self {
- DocumentMatchingFunction::Url(ref url) => url.as_str(),
- DocumentMatchingFunction::UrlPrefix(ref pat) |
- DocumentMatchingFunction::Domain(ref pat) |
- DocumentMatchingFunction::Regexp(ref pat) => pat,
- DocumentMatchingFunction::MediaDocument(kind) => match kind {
- MediaDocumentKind::All => "all",
- MediaDocumentKind::Image => "image",
- MediaDocumentKind::Plugin => "plugin",
- MediaDocumentKind::Video => "video",
- },
- DocumentMatchingFunction::PlainTextDocument(()) |
- DocumentMatchingFunction::UnobservableDocument(()) => "",
- });
- unsafe { Gecko_DocumentRule_UseForPresentation(device.document(), &*pattern, func) }
- }
-
- #[cfg(not(feature = "gecko"))]
- /// Evaluate a URL matching function.
- pub fn evaluate(&self, _: &Device) -> bool {
- false
- }
-}
-
-/// A `@document` rule's condition.
-///
-/// <https://www.w3.org/TR/2012/WD-css3-conditional-20120911/#at-document>
-///
-/// The `@document` rule's condition is written as a comma-separated list of
-/// URL matching functions, and the condition evaluates to true whenever any
-/// one of those functions evaluates to true.
-#[derive(Clone, Debug, ToCss, ToShmem)]
-#[css(comma)]
-pub struct DocumentCondition(#[css(iterable)] Vec<DocumentMatchingFunction>);
-
-impl DocumentCondition {
- /// Parse a document condition.
- pub fn parse<'i, 't>(
- context: &ParserContext,
- input: &mut Parser<'i, 't>,
- ) -> Result<Self, ParseError<'i>> {
- let conditions =
- input.parse_comma_separated(|input| DocumentMatchingFunction::parse(context, input))?;
-
- let condition = DocumentCondition(conditions);
- if !condition.allowed_in(context) {
- return Err(input.new_error(BasicParseErrorKind::AtRuleInvalid("-moz-document".into())));
- }
- Ok(condition)
- }
-
- /// Evaluate a document condition.
- pub fn evaluate(&self, device: &Device) -> bool {
- self.0
- .iter()
- .any(|url_matching_function| url_matching_function.evaluate(device))
- }
-
- #[cfg(feature = "servo")]
- fn allowed_in(&self, _: &ParserContext) -> bool {
- false
- }
-
- #[cfg(feature = "gecko")]
- fn allowed_in(&self, context: &ParserContext) -> bool {
- use static_prefs::pref;
-
- if context.in_ua_or_chrome_sheet() {
- return true;
- }
-
- if pref!("layout.css.moz-document.content.enabled") {
- return true;
- }
-
- // Allow a single url-prefix() for compatibility.
- //
- // See bug 1446470 and dependencies.
- if self.0.len() != 1 {
- return false;
- }
-
- // NOTE(emilio): This technically allows url-prefix("") too, but...
- match self.0[0] {
- DocumentMatchingFunction::UrlPrefix(ref prefix) => prefix.is_empty(),
- _ => false,
- }
- }
-}
diff --git a/components/style/stylesheets/font_face_rule.rs b/components/style/stylesheets/font_face_rule.rs
deleted file mode 100644
index 78f3b338b22..00000000000
--- a/components/style/stylesheets/font_face_rule.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-/* 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/. */
-
-#![allow(missing_docs)]
-
-pub use crate::font_face::FontFaceRuleData as FontFaceRule;
diff --git a/components/style/stylesheets/font_feature_values_rule.rs b/components/style/stylesheets/font_feature_values_rule.rs
deleted file mode 100644
index 06016ec2bd9..00000000000
--- a/components/style/stylesheets/font_feature_values_rule.rs
+++ /dev/null
@@ -1,490 +0,0 @@
-/* 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/. */
-
-//! The [`@font-feature-values`][font-feature-values] at-rule.
-//!
-//! [font-feature-values]: https://drafts.csswg.org/css-fonts-3/#at-font-feature-values-rule
-
-use crate::error_reporting::ContextualParseError;
-#[cfg(feature = "gecko")]
-use crate::gecko_bindings::bindings::Gecko_AppendFeatureValueHashEntry;
-#[cfg(feature = "gecko")]
-use crate::gecko_bindings::structs::{self, gfxFontFeatureValueSet, nsTArray};
-use crate::parser::{Parse, ParserContext};
-use crate::shared_lock::{SharedRwLockReadGuard, ToCssWithGuard};
-use crate::str::CssStringWriter;
-use crate::stylesheets::CssRuleType;
-use crate::values::computed::font::FamilyName;
-use crate::values::serialize_atom_identifier;
-use crate::Atom;
-use cssparser::{
- AtRuleParser, BasicParseErrorKind, CowRcStr, DeclarationParser, Parser, ParserState,
- QualifiedRuleParser, RuleBodyItemParser, RuleBodyParser, SourceLocation, Token,
-};
-use std::fmt::{self, Write};
-use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
-
-/// A @font-feature-values block declaration.
-/// It is `<ident>: <integer>+`.
-/// This struct can take 3 value types.
-/// - `SingleValue` is to keep just one unsigned integer value.
-/// - `PairValues` is to keep one or two unsigned integer values.
-/// - `VectorValues` is to keep a list of unsigned integer values.
-#[derive(Clone, Debug, PartialEq, ToShmem)]
-pub struct FFVDeclaration<T> {
- /// An `<ident>` for declaration name.
- pub name: Atom,
- /// An `<integer>+` for declaration value.
- pub value: T,
-}
-
-impl<T: ToCss> ToCss for FFVDeclaration<T> {
- fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
- where
- W: Write,
- {
- serialize_atom_identifier(&self.name, dest)?;
- dest.write_str(": ")?;
- self.value.to_css(dest)?;
- dest.write_char(';')
- }
-}
-
-/// A trait for @font-feature-values rule to gecko values conversion.
-#[cfg(feature = "gecko")]
-pub trait ToGeckoFontFeatureValues {
- /// Sets the equivalent of declaration to gecko `nsTArray<u32>` array.
- fn to_gecko_font_feature_values(&self, array: &mut nsTArray<u32>);
-}
-
-/// A @font-feature-values block declaration value that keeps one value.
-#[derive(Clone, Debug, PartialEq, ToCss, ToShmem)]
-pub struct SingleValue(pub u32);
-
-impl Parse for SingleValue {
- fn parse<'i, 't>(
- _context: &ParserContext,
- input: &mut Parser<'i, 't>,
- ) -> Result<SingleValue, ParseError<'i>> {
- let location = input.current_source_location();
- match *input.next()? {
- Token::Number {
- int_value: Some(v), ..
- } if v >= 0 => Ok(SingleValue(v as u32)),
- ref t => Err(location.new_unexpected_token_error(t.clone())),
- }
- }
-}
-
-#[cfg(feature = "gecko")]
-impl ToGeckoFontFeatureValues for SingleValue {
- fn to_gecko_font_feature_values(&self, array: &mut nsTArray<u32>) {
- unsafe {
- array.set_len_pod(1);
- }
- array[0] = self.0 as u32;
- }
-}
-
-/// A @font-feature-values block declaration value that keeps one or two values.
-#[derive(Clone, Debug, PartialEq, ToCss, ToShmem)]
-pub struct PairValues(pub u32, pub Option<u32>);
-
-impl Parse for PairValues {
- fn parse<'i, 't>(
- _context: &ParserContext,
- input: &mut Parser<'i, 't>,
- ) -> Result<PairValues, ParseError<'i>> {
- let location = input.current_source_location();
- let first = match *input.next()? {
- Token::Number {
- int_value: Some(a), ..
- } if a >= 0 => a as u32,
- ref t => return Err(location.new_unexpected_token_error(t.clone())),
- };
- let location = input.current_source_location();
- match input.next() {
- Ok(&Token::Number {
- int_value: Some(b), ..
- }) if b >= 0 => Ok(PairValues(first, Some(b as u32))),
- // It can't be anything other than number.
- Ok(t) => Err(location.new_unexpected_token_error(t.clone())),
- // It can be just one value.
- Err(_) => Ok(PairValues(first, None)),
- }
- }
-}
-
-#[cfg(feature = "gecko")]
-impl ToGeckoFontFeatureValues for PairValues {
- fn to_gecko_font_feature_values(&self, array: &mut nsTArray<u32>) {
- let len = if self.1.is_some() { 2 } else { 1 };
-
- unsafe {
- array.set_len_pod(len);
- }
- array[0] = self.0 as u32;
- if let Some(second) = self.1 {
- array[1] = second as u32;
- };
- }
-}
-
-/// A @font-feature-values block declaration value that keeps a list of values.
-#[derive(Clone, Debug, PartialEq, ToCss, ToShmem)]
-pub struct VectorValues(#[css(iterable)] pub Vec<u32>);
-
-impl Parse for VectorValues {
- fn parse<'i, 't>(
- _context: &ParserContext,
- input: &mut Parser<'i, 't>,
- ) -> Result<VectorValues, ParseError<'i>> {
- let mut vec = vec![];
- loop {
- let location = input.current_source_location();
- match input.next() {
- Ok(&Token::Number {
- int_value: Some(a), ..
- }) if a >= 0 => {
- vec.push(a as u32);
- },
- // It can't be anything other than number.
- Ok(t) => return Err(location.new_unexpected_token_error(t.clone())),
- Err(_) => break,
- }
- }
-
- if vec.len() == 0 {
- return Err(input.new_error(BasicParseErrorKind::EndOfInput));
- }
-
- Ok(VectorValues(vec))
- }
-}
-
-#[cfg(feature = "gecko")]
-impl ToGeckoFontFeatureValues for VectorValues {
- fn to_gecko_font_feature_values(&self, array: &mut nsTArray<u32>) {
- array.assign_from_iter_pod(self.0.iter().map(|v| *v));
- }
-}
-
-/// Parses a list of `FamilyName`s.
-pub fn parse_family_name_list<'i, 't>(
- context: &ParserContext,
- input: &mut Parser<'i, 't>,
-) -> Result<Vec<FamilyName>, ParseError<'i>> {
- input
- .parse_comma_separated(|i| FamilyName::parse(context, i))
- .map_err(|e| e.into())
-}
-
-/// @font-feature-values inside block parser. Parses a list of `FFVDeclaration`.
-/// (`<ident>: <integer>+`)
-struct FFVDeclarationsParser<'a, 'b: 'a, T: 'a> {
- context: &'a ParserContext<'b>,
- declarations: &'a mut Vec<FFVDeclaration<T>>,
-}
-
-/// Default methods reject all at rules.
-impl<'a, 'b, 'i, T> AtRuleParser<'i> for FFVDeclarationsParser<'a, 'b, T> {
- type Prelude = ();
- type AtRule = ();
- type Error = StyleParseErrorKind<'i>;
-}
-
-impl<'a, 'b, 'i, T> QualifiedRuleParser<'i> for FFVDeclarationsParser<'a, 'b, T> {
- type Prelude = ();
- type QualifiedRule = ();
- type Error = StyleParseErrorKind<'i>;
-}
-
-impl<'a, 'b, 'i, T> DeclarationParser<'i> for FFVDeclarationsParser<'a, 'b, T>
-where
- T: Parse,
-{
- type Declaration = ();
- type Error = StyleParseErrorKind<'i>;
-
- fn parse_value<'t>(
- &mut self,
- name: CowRcStr<'i>,
- input: &mut Parser<'i, 't>,
- ) -> Result<(), ParseError<'i>> {
- let value = input.parse_entirely(|i| T::parse(self.context, i))?;
- let new = FFVDeclaration {
- name: Atom::from(&*name),
- value,
- };
- update_or_push(&mut self.declarations, new);
- Ok(())
- }
-}
-
-impl<'a, 'b, 'i, T> RuleBodyItemParser<'i, (), StyleParseErrorKind<'i>>
- for FFVDeclarationsParser<'a, 'b, T>
-where
- T: Parse,
-{
- fn parse_declarations(&self) -> bool {
- true
- }
- fn parse_qualified(&self) -> bool {
- false
- }
-}
-
-macro_rules! font_feature_values_blocks {
- (
- blocks = [
- $( #[$doc: meta] $name: tt $ident: ident / $ident_camel: ident / $gecko_enum: ident: $ty: ty, )*
- ]
- ) => {
- /// The [`@font-feature-values`][font-feature-values] at-rule.
- ///
- /// [font-feature-values]: https://drafts.csswg.org/css-fonts-3/#at-font-feature-values-rule
- #[derive(Clone, Debug, PartialEq, ToShmem)]
- pub struct FontFeatureValuesRule {
- /// Font family list for @font-feature-values rule.
- /// Family names cannot contain generic families. FamilyName
- /// also accepts only non-generic names.
- pub family_names: Vec<FamilyName>,
- $(
- #[$doc]
- pub $ident: Vec<FFVDeclaration<$ty>>,
- )*
- /// The line and column of the rule's source code.
- pub source_location: SourceLocation,
- }
-
- impl FontFeatureValuesRule {
- /// Creates an empty FontFeatureValuesRule with given location and family name list.
- fn new(family_names: Vec<FamilyName>, location: SourceLocation) -> Self {
- FontFeatureValuesRule {
- family_names: family_names,
- $(
- $ident: vec![],
- )*
- source_location: location,
- }
- }
-
- /// Parses a `FontFeatureValuesRule`.
- pub fn parse(
- context: &ParserContext,
- input: &mut Parser,
- family_names: Vec<FamilyName>,
- location: SourceLocation,
- ) -> Self {
- let mut rule = FontFeatureValuesRule::new(family_names, location);
- let mut parser = FontFeatureValuesRuleParser {
- context,
- rule: &mut rule,
- };
- let mut iter = RuleBodyParser::new(input, &mut parser);
- while let Some(result) = iter.next() {
- if let Err((error, slice)) = result {
- let location = error.location;
- let error = ContextualParseError::UnsupportedRule(slice, error);
- context.log_css_error(location, error);
- }
- }
- rule
- }
-
- /// Prints inside of `@font-feature-values` block.
- pub fn value_to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
- where
- W: Write,
- {
- $(
- if self.$ident.len() > 0 {
- dest.write_str(concat!("@", $name, " {\n"))?;
- let iter = self.$ident.iter();
- for val in iter {
- val.to_css(dest)?;
- dest.write_str("\n")?
- }
- dest.write_str("}\n")?
- }
- )*
- Ok(())
- }
-
- /// Returns length of all at-rules.
- pub fn len(&self) -> usize {
- let mut len = 0;
- $(
- len += self.$ident.len();
- )*
- len
- }
-
- /// Convert to Gecko gfxFontFeatureValueSet.
- #[cfg(feature = "gecko")]
- pub fn set_at_rules(&self, dest: *mut gfxFontFeatureValueSet) {
- for ref family in self.family_names.iter() {
- let family = family.name.to_ascii_lowercase();
- $(
- if self.$ident.len() > 0 {
- for val in self.$ident.iter() {
- let array = unsafe {
- Gecko_AppendFeatureValueHashEntry(
- dest,
- family.as_ptr(),
- structs::$gecko_enum,
- val.name.as_ptr()
- )
- };
- unsafe {
- val.value.to_gecko_font_feature_values(&mut *array);
- }
- }
- }
- )*
- }
- }
- }
-
- impl ToCssWithGuard for FontFeatureValuesRule {
- fn to_css(&self, _guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
- dest.write_str("@font-feature-values ")?;
- self.family_names.to_css(&mut CssWriter::new(dest))?;
- dest.write_str(" {\n")?;
- self.value_to_css(&mut CssWriter::new(dest))?;
- dest.write_char('}')
- }
- }
-
- /// Updates with new value if same `ident` exists, otherwise pushes to the vector.
- fn update_or_push<T>(vec: &mut Vec<FFVDeclaration<T>>, element: FFVDeclaration<T>) {
- if let Some(item) = vec.iter_mut().find(|item| item.name == element.name) {
- item.value = element.value;
- } else {
- vec.push(element);
- }
- }
-
- /// Keeps the information about block type like @swash, @styleset etc.
- enum BlockType {
- $(
- $ident_camel,
- )*
- }
-
- /// Parser for `FontFeatureValuesRule`. Parses all blocks
- /// <feature-type> {
- /// <feature-value-declaration-list>
- /// }
- /// <feature-type> = @stylistic | @historical-forms | @styleset |
- /// @character-variant | @swash | @ornaments | @annotation
- struct FontFeatureValuesRuleParser<'a> {
- context: &'a ParserContext<'a>,
- rule: &'a mut FontFeatureValuesRule,
- }
-
- /// Default methods reject all qualified rules.
- impl<'a, 'i> QualifiedRuleParser<'i> for FontFeatureValuesRuleParser<'a> {
- type Prelude = ();
- type QualifiedRule = ();
- type Error = StyleParseErrorKind<'i>;
- }
-
- impl<'a, 'i> AtRuleParser<'i> for FontFeatureValuesRuleParser<'a> {
- type Prelude = BlockType;
- type AtRule = ();
- type Error = StyleParseErrorKind<'i>;
-
- fn parse_prelude<'t>(
- &mut self,
- name: CowRcStr<'i>,
- input: &mut Parser<'i, 't>,
- ) -> Result<BlockType, ParseError<'i>> {
- match_ignore_ascii_case! { &*name,
- $(
- $name => Ok(BlockType::$ident_camel),
- )*
- _ => Err(input.new_error(BasicParseErrorKind::AtRuleBodyInvalid)),
- }
- }
-
- fn parse_block<'t>(
- &mut self,
- prelude: BlockType,
- _: &ParserState,
- input: &mut Parser<'i, 't>
- ) -> Result<Self::AtRule, ParseError<'i>> {
- debug_assert!(self.context.rule_types().contains(CssRuleType::FontFeatureValues));
- match prelude {
- $(
- BlockType::$ident_camel => {
- let mut parser = FFVDeclarationsParser {
- context: &self.context,
- declarations: &mut self.rule.$ident,
- };
-
- let mut iter = RuleBodyParser::new(input, &mut parser);
- while let Some(declaration) = iter.next() {
- if let Err((error, slice)) = declaration {
- let location = error.location;
- let error = ContextualParseError::UnsupportedKeyframePropertyDeclaration(
- slice, error
- );
- self.context.log_css_error(location, error);
- }
- }
- },
- )*
- }
-
- Ok(())
- }
- }
-
- impl<'a, 'i> DeclarationParser<'i> for FontFeatureValuesRuleParser<'a> {
- type Declaration = ();
- type Error = StyleParseErrorKind<'i>;
- }
-
- impl<'a, 'i> RuleBodyItemParser<'i, (), StyleParseErrorKind<'i>> for FontFeatureValuesRuleParser<'a> {
- fn parse_declarations(&self) -> bool { false }
- fn parse_qualified(&self) -> bool { true }
- }
- }
-}
-
-font_feature_values_blocks! {
- blocks = [
- #[doc = "A @swash blocksck. \
- Specifies a feature name that will work with the swash() \
- functional notation of font-variant-alternates."]
- "swash" swash / Swash / NS_FONT_VARIANT_ALTERNATES_SWASH: SingleValue,
-
- #[doc = "A @stylistic block. \
- Specifies a feature name that will work with the annotation() \
- functional notation of font-variant-alternates."]
- "stylistic" stylistic / Stylistic / NS_FONT_VARIANT_ALTERNATES_STYLISTIC: SingleValue,
-
- #[doc = "A @ornaments block. \
- Specifies a feature name that will work with the ornaments() ] \
- functional notation of font-variant-alternates."]
- "ornaments" ornaments / Ornaments / NS_FONT_VARIANT_ALTERNATES_ORNAMENTS: SingleValue,
-
- #[doc = "A @annotation block. \
- Specifies a feature name that will work with the stylistic() \
- functional notation of font-variant-alternates."]
- "annotation" annotation / Annotation / NS_FONT_VARIANT_ALTERNATES_ANNOTATION: SingleValue,
-
- #[doc = "A @character-variant block. \
- Specifies a feature name that will work with the styleset() \
- functional notation of font-variant-alternates. The value can be a pair."]
- "character-variant" character_variant / CharacterVariant / NS_FONT_VARIANT_ALTERNATES_CHARACTER_VARIANT:
- PairValues,
-
- #[doc = "A @styleset block. \
- Specifies a feature name that will work with the character-variant() \
- functional notation of font-variant-alternates. The value can be a list."]
- "styleset" styleset / Styleset / NS_FONT_VARIANT_ALTERNATES_STYLESET: VectorValues,
- ]
-}
diff --git a/components/style/stylesheets/font_palette_values_rule.rs b/components/style/stylesheets/font_palette_values_rule.rs
deleted file mode 100644
index c604f9b3c6e..00000000000
--- a/components/style/stylesheets/font_palette_values_rule.rs
+++ /dev/null
@@ -1,268 +0,0 @@
-/* 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/. */
-
-//! The [`@font-palette-values`][font-palette-values] at-rule.
-//!
-//! [font-palette-values]: https://drafts.csswg.org/css-fonts/#font-palette-values
-
-use crate::error_reporting::ContextualParseError;
-#[cfg(feature = "gecko")]
-use crate::gecko_bindings::{
- bindings::Gecko_AppendPaletteValueHashEntry,
- bindings::{Gecko_SetFontPaletteBase, Gecko_SetFontPaletteOverride},
- structs::gfx::FontPaletteValueSet,
- structs::gfx::FontPaletteValueSet_PaletteValues_kDark,
- structs::gfx::FontPaletteValueSet_PaletteValues_kLight,
-};
-use crate::parser::{Parse, ParserContext};
-use crate::shared_lock::{SharedRwLockReadGuard, ToCssWithGuard};
-use crate::str::CssStringWriter;
-use crate::stylesheets::font_feature_values_rule::parse_family_name_list;
-use crate::values::computed::font::FamilyName;
-use crate::values::specified::Color as SpecifiedColor;
-use crate::values::specified::NonNegativeInteger;
-use crate::values::DashedIdent;
-use cssparser::{
- AtRuleParser, CowRcStr, DeclarationParser, Parser, QualifiedRuleParser, RuleBodyItemParser,
- RuleBodyParser, SourceLocation,
-};
-use selectors::parser::SelectorParseErrorKind;
-use std::fmt::{self, Write};
-use style_traits::{Comma, OneOrMoreSeparated};
-use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
-
-#[allow(missing_docs)]
-#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToShmem)]
-pub struct FontPaletteOverrideColor {
- index: NonNegativeInteger,
- color: SpecifiedColor,
-}
-
-impl Parse for FontPaletteOverrideColor {
- fn parse<'i, 't>(
- context: &ParserContext,
- input: &mut Parser<'i, 't>,
- ) -> Result<FontPaletteOverrideColor, ParseError<'i>> {
- let index = NonNegativeInteger::parse(context, input)?;
- let location = input.current_source_location();
- let color = SpecifiedColor::parse(context, input)?;
- // Only absolute colors are accepted here.
- if let SpecifiedColor::Absolute { .. } = color {
- Ok(FontPaletteOverrideColor { index, color })
- } else {
- Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError))
- }
- }
-}
-
-impl ToCss for FontPaletteOverrideColor {
- fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
- where
- W: fmt::Write,
- {
- self.index.to_css(dest)?;
- dest.write_char(' ')?;
- self.color.to_css(dest)
- }
-}
-
-impl OneOrMoreSeparated for FontPaletteOverrideColor {
- type S = Comma;
-}
-
-impl OneOrMoreSeparated for FamilyName {
- type S = Comma;
-}
-
-#[allow(missing_docs)]
-#[derive(Clone, Debug, MallocSizeOf, Parse, PartialEq, ToCss, ToShmem)]
-pub enum FontPaletteBase {
- Light,
- Dark,
- Index(NonNegativeInteger),
-}
-
-/// The [`@font-palette-values`][font-palette-values] at-rule.
-///
-/// [font-palette-values]: https://drafts.csswg.org/css-fonts/#font-palette-values
-#[derive(Clone, Debug, PartialEq, ToShmem)]
-pub struct FontPaletteValuesRule {
- /// Palette name.
- pub name: DashedIdent,
- /// Font family list for @font-palette-values rule.
- /// Family names cannot contain generic families. FamilyName
- /// also accepts only non-generic names.
- pub family_names: Vec<FamilyName>,
- /// The base palette.
- pub base_palette: Option<FontPaletteBase>,
- /// The list of override colors.
- pub override_colors: Vec<FontPaletteOverrideColor>,
- /// The line and column of the rule's source code.
- pub source_location: SourceLocation,
-}
-
-impl FontPaletteValuesRule {
- /// Creates an empty FontPaletteValuesRule with given location and name.
- fn new(name: DashedIdent, location: SourceLocation) -> Self {
- FontPaletteValuesRule {
- name,
- family_names: vec![],
- base_palette: None,
- override_colors: vec![],
- source_location: location,
- }
- }
-
- /// Parses a `FontPaletteValuesRule`.
- pub fn parse(
- context: &ParserContext,
- input: &mut Parser,
- name: DashedIdent,
- location: SourceLocation,
- ) -> Self {
- let mut rule = FontPaletteValuesRule::new(name, location);
- let mut parser = FontPaletteValuesDeclarationParser {
- context,
- rule: &mut rule,
- };
- let mut iter = RuleBodyParser::new(input, &mut parser);
- while let Some(declaration) = iter.next() {
- if let Err((error, slice)) = declaration {
- let location = error.location;
- let error =
- ContextualParseError::UnsupportedFontPaletteValuesDescriptor(slice, error);
- context.log_css_error(location, error);
- }
- }
- rule
- }
-
- /// Prints inside of `@font-palette-values` block.
- fn value_to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
- where
- W: Write,
- {
- if !self.family_names.is_empty() {
- dest.write_str("font-family: ")?;
- self.family_names.to_css(dest)?;
- dest.write_str("; ")?;
- }
- if let Some(base) = &self.base_palette {
- dest.write_str("base-palette: ")?;
- base.to_css(dest)?;
- dest.write_str("; ")?;
- }
- if !self.override_colors.is_empty() {
- dest.write_str("override-colors: ")?;
- self.override_colors.to_css(dest)?;
- dest.write_str("; ")?;
- }
- Ok(())
- }
-
- /// Convert to Gecko FontPaletteValueSet.
- #[cfg(feature = "gecko")]
- pub fn to_gecko_palette_value_set(&self, dest: *mut FontPaletteValueSet) {
- for ref family in self.family_names.iter() {
- let family = family.name.to_ascii_lowercase();
- let palette_values = unsafe {
- Gecko_AppendPaletteValueHashEntry(dest, family.as_ptr(), self.name.0.as_ptr())
- };
- if let Some(base_palette) = &self.base_palette {
- unsafe {
- Gecko_SetFontPaletteBase(
- palette_values,
- match &base_palette {
- FontPaletteBase::Light => FontPaletteValueSet_PaletteValues_kLight,
- FontPaletteBase::Dark => FontPaletteValueSet_PaletteValues_kDark,
- FontPaletteBase::Index(i) => i.0.value() as i32,
- },
- );
- }
- }
- for c in &self.override_colors {
- if let SpecifiedColor::Absolute(ref absolute) = c.color {
- unsafe {
- Gecko_SetFontPaletteOverride(
- palette_values,
- c.index.0.value(),
- (&absolute.color) as *const _ as *mut _,
- );
- }
- }
- }
- }
- }
-}
-
-impl ToCssWithGuard for FontPaletteValuesRule {
- fn to_css(&self, _guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
- dest.write_str("@font-palette-values ")?;
- self.name.to_css(&mut CssWriter::new(dest))?;
- dest.write_str(" { ")?;
- self.value_to_css(&mut CssWriter::new(dest))?;
- dest.write_char('}')
- }
-}
-
-/// Parser for declarations in `FontPaletteValuesRule`.
-struct FontPaletteValuesDeclarationParser<'a> {
- context: &'a ParserContext<'a>,
- rule: &'a mut FontPaletteValuesRule,
-}
-
-impl<'a, 'i> AtRuleParser<'i> for FontPaletteValuesDeclarationParser<'a> {
- type Prelude = ();
- type AtRule = ();
- type Error = StyleParseErrorKind<'i>;
-}
-
-impl<'a, 'i> QualifiedRuleParser<'i> for FontPaletteValuesDeclarationParser<'a> {
- type Prelude = ();
- type QualifiedRule = ();
- type Error = StyleParseErrorKind<'i>;
-}
-
-fn parse_override_colors<'i, 't>(
- context: &ParserContext,
- input: &mut Parser<'i, 't>,
-) -> Result<Vec<FontPaletteOverrideColor>, ParseError<'i>> {
- input.parse_comma_separated(|i| FontPaletteOverrideColor::parse(context, i))
-}
-
-impl<'a, 'b, 'i> DeclarationParser<'i> for FontPaletteValuesDeclarationParser<'a> {
- type Declaration = ();
- type Error = StyleParseErrorKind<'i>;
-
- fn parse_value<'t>(
- &mut self,
- name: CowRcStr<'i>,
- input: &mut Parser<'i, 't>,
- ) -> Result<(), ParseError<'i>> {
- match_ignore_ascii_case! { &*name,
- "font-family" => {
- self.rule.family_names = parse_family_name_list(self.context, input)?
- },
- "base-palette" => {
- self.rule.base_palette = Some(input.parse_entirely(|i| FontPaletteBase::parse(self.context, i))?)
- },
- "override-colors" => {
- self.rule.override_colors = parse_override_colors(self.context, input)?
- },
- _ => return Err(input.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(name.clone()))),
- }
- Ok(())
- }
-}
-
-impl<'a, 'i> RuleBodyItemParser<'i, (), StyleParseErrorKind<'i>>
- for FontPaletteValuesDeclarationParser<'a>
-{
- fn parse_declarations(&self) -> bool {
- true
- }
- fn parse_qualified(&self) -> bool {
- false
- }
-}
diff --git a/components/style/stylesheets/import_rule.rs b/components/style/stylesheets/import_rule.rs
deleted file mode 100644
index e7ea2748465..00000000000
--- a/components/style/stylesheets/import_rule.rs
+++ /dev/null
@@ -1,332 +0,0 @@
-/* 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/. */
-
-//! The [`@import`][import] at-rule.
-//!
-//! [import]: https://drafts.csswg.org/css-cascade-3/#at-import
-
-use crate::media_queries::MediaList;
-use crate::parser::{Parse, ParserContext};
-use crate::shared_lock::{
- DeepCloneParams, DeepCloneWithLock, SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard,
-};
-use crate::str::CssStringWriter;
-use crate::stylesheets::{
- layer_rule::LayerName, supports_rule::SupportsCondition, CssRule, CssRuleType,
- StylesheetInDocument,
-};
-use crate::values::CssUrl;
-use cssparser::{Parser, SourceLocation};
-use std::fmt::{self, Write};
-use style_traits::{CssWriter, ToCss};
-use to_shmem::{self, SharedMemoryBuilder, ToShmem};
-
-/// A sheet that is held from an import rule.
-#[cfg(feature = "gecko")]
-#[derive(Debug)]
-pub enum ImportSheet {
- /// A bonafide stylesheet.
- Sheet(crate::gecko::data::GeckoStyleSheet),
-
- /// An @import created while parsing off-main-thread, whose Gecko sheet has
- /// yet to be created and attached.
- Pending,
-
- /// An @import created with a false <supports-condition>, so will never be fetched.
- Refused,
-}
-
-#[cfg(feature = "gecko")]
-impl ImportSheet {
- /// Creates a new ImportSheet from a GeckoStyleSheet.
- pub fn new(sheet: crate::gecko::data::GeckoStyleSheet) -> Self {
- ImportSheet::Sheet(sheet)
- }
-
- /// Creates a pending ImportSheet for a load that has not started yet.
- pub fn new_pending() -> Self {
- ImportSheet::Pending
- }
-
- /// Creates a refused ImportSheet for a load that will not happen.
- pub fn new_refused() -> Self {
- ImportSheet::Refused
- }
-
- /// Returns a reference to the GeckoStyleSheet in this ImportSheet, if it
- /// exists.
- pub fn as_sheet(&self) -> Option<&crate::gecko::data::GeckoStyleSheet> {
- match *self {
- ImportSheet::Sheet(ref s) => {
- debug_assert!(!s.hack_is_null());
- if s.hack_is_null() {
- return None;
- }
- Some(s)
- },
- ImportSheet::Refused | ImportSheet::Pending => None,
- }
- }
-
- /// Returns the media list for this import rule.
- pub fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList> {
- self.as_sheet().and_then(|s| s.media(guard))
- }
-
- /// Returns the rule list for this import rule.
- pub fn rules<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> &'a [CssRule] {
- match self.as_sheet() {
- Some(s) => s.rules(guard),
- None => &[],
- }
- }
-}
-
-#[cfg(feature = "gecko")]
-impl DeepCloneWithLock for ImportSheet {
- fn deep_clone_with_lock(
- &self,
- _lock: &SharedRwLock,
- _guard: &SharedRwLockReadGuard,
- params: &DeepCloneParams,
- ) -> Self {
- use crate::gecko::data::GeckoStyleSheet;
- use crate::gecko_bindings::bindings;
- match *self {
- ImportSheet::Sheet(ref s) => {
- let clone = unsafe {
- bindings::Gecko_StyleSheet_Clone(s.raw() as *const _, params.reference_sheet)
- };
- ImportSheet::Sheet(unsafe { GeckoStyleSheet::from_addrefed(clone) })
- },
- ImportSheet::Pending => ImportSheet::Pending,
- ImportSheet::Refused => ImportSheet::Refused,
- }
- }
-}
-
-/// A sheet that is held from an import rule.
-#[cfg(feature = "servo")]
-#[derive(Debug)]
-pub enum ImportSheet {
- /// A bonafide stylesheet.
- Sheet(::servo_arc::Arc<crate::stylesheets::Stylesheet>),
-
- /// An @import created with a false <supports-condition>, so will never be fetched.
- Refused,
-}
-
-#[cfg(feature = "servo")]
-impl ImportSheet {
- /// Creates a new ImportSheet from a stylesheet.
- pub fn new(sheet: ::servo_arc::Arc<crate::stylesheets::Stylesheet>) -> Self {
- ImportSheet::Sheet(sheet)
- }
-
- /// Creates a refused ImportSheet for a load that will not happen.
- pub fn new_refused() -> Self {
- ImportSheet::Refused
- }
-
- /// Returns a reference to the stylesheet in this ImportSheet, if it exists.
- pub fn as_sheet(&self) -> Option<&::servo_arc::Arc<crate::stylesheets::Stylesheet>> {
- match *self {
- ImportSheet::Sheet(ref s) => Some(s),
- ImportSheet::Refused => None,
- }
- }
-
- /// Returns the media list for this import rule.
- pub fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList> {
- self.as_sheet().and_then(|s| s.media(guard))
- }
-
- /// Returns the rules for this import rule.
- pub fn rules<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> &'a [CssRule] {
- match self.as_sheet() {
- Some(s) => s.rules(guard),
- None => &[],
- }
- }
-}
-
-#[cfg(feature = "servo")]
-impl DeepCloneWithLock for ImportSheet {
- fn deep_clone_with_lock(
- &self,
- _lock: &SharedRwLock,
- _guard: &SharedRwLockReadGuard,
- _params: &DeepCloneParams,
- ) -> Self {
- match *self {
- ImportSheet::Sheet(ref s) => {
- use servo_arc::Arc;
- ImportSheet::Sheet(Arc::new((&**s).clone()))
- },
- ImportSheet::Refused => ImportSheet::Refused,
- }
- }
-}
-
-/// The layer specified in an import rule (can be none, anonymous, or named).
-#[derive(Debug, Clone)]
-pub enum ImportLayer {
- /// No layer specified
- None,
-
- /// Anonymous layer (`layer`)
- Anonymous,
-
- /// Named layer (`layer(name)`)
- Named(LayerName),
-}
-
-/// The supports condition in an import rule.
-#[derive(Debug, Clone)]
-pub struct ImportSupportsCondition {
- /// The supports condition.
- pub condition: SupportsCondition,
-
- /// If the import is enabled, from the result of the import condition.
- pub enabled: bool,
-}
-
-impl ToCss for ImportLayer {
- fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
- where
- W: Write,
- {
- match *self {
- ImportLayer::None => Ok(()),
- ImportLayer::Anonymous => dest.write_str("layer"),
- ImportLayer::Named(ref name) => {
- dest.write_str("layer(")?;
- name.to_css(dest)?;
- dest.write_char(')')
- },
- }
- }
-}
-
-/// The [`@import`][import] at-rule.
-///
-/// [import]: https://drafts.csswg.org/css-cascade-3/#at-import
-#[derive(Debug)]
-pub struct ImportRule {
- /// The `<url>` this `@import` rule is loading.
- pub url: CssUrl,
-
- /// The stylesheet is always present. However, in the case of gecko async
- /// parsing, we don't actually have a Gecko sheet at first, and so the
- /// ImportSheet just has stub behavior until it appears.
- pub stylesheet: ImportSheet,
-
- /// A <supports-condition> for the rule.
- pub supports: Option<ImportSupportsCondition>,
-
- /// A `layer()` function name.
- pub layer: ImportLayer,
-
- /// The line and column of the rule's source code.
- pub source_location: SourceLocation,
-}
-
-impl ImportRule {
- /// Parses the layer() / layer / supports() part of the import header, as per
- /// https://drafts.csswg.org/css-cascade-5/#at-import:
- ///
- /// [ layer | layer(<layer-name>) ]?
- /// [ supports([ <supports-condition> | <declaration> ]) ]?
- ///
- /// We do this here so that the import preloader can look at this without having to parse the
- /// whole import rule or parse the media query list or what not.
- pub fn parse_layer_and_supports<'i, 't>(
- input: &mut Parser<'i, 't>,
- context: &mut ParserContext,
- ) -> (ImportLayer, Option<ImportSupportsCondition>) {
- let layer = if input
- .try_parse(|input| input.expect_ident_matching("layer"))
- .is_ok()
- {
- ImportLayer::Anonymous
- } else {
- input
- .try_parse(|input| {
- input.expect_function_matching("layer")?;
- input
- .parse_nested_block(|input| LayerName::parse(context, input))
- .map(|name| ImportLayer::Named(name))
- })
- .ok()
- .unwrap_or(ImportLayer::None)
- };
-
- let supports = if !static_prefs::pref!("layout.css.import-supports.enabled") {
- None
- } else {
- input
- .try_parse(SupportsCondition::parse_for_import)
- .map(|condition| {
- let enabled = context
- .nest_for_rule(CssRuleType::Style, |context| condition.eval(context));
- ImportSupportsCondition { condition, enabled }
- })
- .ok()
- };
-
- (layer, supports)
- }
-}
-
-impl ToShmem for ImportRule {
- fn to_shmem(&self, _builder: &mut SharedMemoryBuilder) -> to_shmem::Result<Self> {
- Err(String::from(
- "ToShmem failed for ImportRule: cannot handle imported style sheets",
- ))
- }
-}
-
-impl DeepCloneWithLock for ImportRule {
- fn deep_clone_with_lock(
- &self,
- lock: &SharedRwLock,
- guard: &SharedRwLockReadGuard,
- params: &DeepCloneParams,
- ) -> Self {
- ImportRule {
- url: self.url.clone(),
- stylesheet: self.stylesheet.deep_clone_with_lock(lock, guard, params),
- supports: self.supports.clone(),
- layer: self.layer.clone(),
- source_location: self.source_location.clone(),
- }
- }
-}
-
-impl ToCssWithGuard for ImportRule {
- fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
- dest.write_str("@import ")?;
- self.url.to_css(&mut CssWriter::new(dest))?;
-
- if !matches!(self.layer, ImportLayer::None) {
- dest.write_char(' ')?;
- self.layer.to_css(&mut CssWriter::new(dest))?;
- }
-
- if let Some(ref supports) = self.supports {
- dest.write_str(" supports(")?;
- supports.condition.to_css(&mut CssWriter::new(dest))?;
- dest.write_char(')')?;
- }
-
- if let Some(media) = self.stylesheet.media(guard) {
- if !media.is_empty() {
- dest.write_char(' ')?;
- media.to_css(&mut CssWriter::new(dest))?;
- }
- }
-
- dest.write_char(';')
- }
-}
diff --git a/components/style/stylesheets/keyframes_rule.rs b/components/style/stylesheets/keyframes_rule.rs
deleted file mode 100644
index 6e5016080e9..00000000000
--- a/components/style/stylesheets/keyframes_rule.rs
+++ /dev/null
@@ -1,691 +0,0 @@
-/* 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/. */
-
-//! Keyframes: https://drafts.csswg.org/css-animations/#keyframes
-
-use crate::error_reporting::ContextualParseError;
-use crate::parser::ParserContext;
-use crate::properties::longhands::animation_composition::single_value::SpecifiedValue as SpecifiedComposition;
-use crate::properties::longhands::transition_timing_function::single_value::SpecifiedValue as SpecifiedTimingFunction;
-use crate::properties::LonghandIdSet;
-use crate::properties::{Importance, PropertyDeclaration};
-use crate::properties::{LonghandId, PropertyDeclarationBlock, PropertyId};
-use crate::properties::{PropertyDeclarationId, SourcePropertyDeclaration};
-use crate::shared_lock::{DeepCloneParams, DeepCloneWithLock, SharedRwLock, SharedRwLockReadGuard};
-use crate::shared_lock::{Locked, ToCssWithGuard};
-use crate::str::CssStringWriter;
-use crate::stylesheets::rule_parser::VendorPrefix;
-use crate::stylesheets::{CssRuleType, StylesheetContents};
-use crate::values::{serialize_percentage, KeyframesName};
-use cssparser::{
- parse_one_rule, AtRuleParser, CowRcStr, DeclarationParser, Parser, ParserInput, ParserState,
- QualifiedRuleParser, RuleBodyItemParser, RuleBodyParser, SourceLocation, Token,
-};
-use servo_arc::Arc;
-use std::borrow::Cow;
-use std::fmt::{self, Write};
-use style_traits::{CssWriter, ParseError, ParsingMode, StyleParseErrorKind, ToCss};
-
-/// A [`@keyframes`][keyframes] rule.
-///
-/// [keyframes]: https://drafts.csswg.org/css-animations/#keyframes
-#[derive(Debug, ToShmem)]
-pub struct KeyframesRule {
- /// The name of the current animation.
- pub name: KeyframesName,
- /// The keyframes specified for this CSS rule.
- pub keyframes: Vec<Arc<Locked<Keyframe>>>,
- /// Vendor prefix type the @keyframes has.
- pub vendor_prefix: Option<VendorPrefix>,
- /// The line and column of the rule's source code.
- pub source_location: SourceLocation,
-}
-
-impl ToCssWithGuard for KeyframesRule {
- // Serialization of KeyframesRule is not specced.
- fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
- dest.write_str("@keyframes ")?;
- self.name.to_css(&mut CssWriter::new(dest))?;
- dest.write_str(" {")?;
- let iter = self.keyframes.iter();
- for lock in iter {
- dest.write_str("\n")?;
- let keyframe = lock.read_with(&guard);
- keyframe.to_css(guard, dest)?;
- }
- dest.write_str("\n}")
- }
-}
-
-impl KeyframesRule {
- /// Returns the index of the last keyframe that matches the given selector.
- /// If the selector is not valid, or no keyframe is found, returns None.
- ///
- /// Related spec:
- /// <https://drafts.csswg.org/css-animations-1/#interface-csskeyframesrule-findrule>
- pub fn find_rule(&self, guard: &SharedRwLockReadGuard, selector: &str) -> Option<usize> {
- let mut input = ParserInput::new(selector);
- if let Ok(selector) = Parser::new(&mut input).parse_entirely(KeyframeSelector::parse) {
- for (i, keyframe) in self.keyframes.iter().enumerate().rev() {
- if keyframe.read_with(guard).selector == selector {
- return Some(i);
- }
- }
- }
- None
- }
-}
-
-impl DeepCloneWithLock for KeyframesRule {
- fn deep_clone_with_lock(
- &self,
- lock: &SharedRwLock,
- guard: &SharedRwLockReadGuard,
- params: &DeepCloneParams,
- ) -> Self {
- KeyframesRule {
- name: self.name.clone(),
- keyframes: self
- .keyframes
- .iter()
- .map(|x| {
- Arc::new(
- lock.wrap(x.read_with(guard).deep_clone_with_lock(lock, guard, params)),
- )
- })
- .collect(),
- vendor_prefix: self.vendor_prefix.clone(),
- source_location: self.source_location.clone(),
- }
- }
-}
-
-/// A number from 0 to 1, indicating the percentage of the animation when this
-/// keyframe should run.
-#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, PartialOrd, ToShmem)]
-pub struct KeyframePercentage(pub f32);
-
-impl ::std::cmp::Ord for KeyframePercentage {
- #[inline]
- fn cmp(&self, other: &Self) -> ::std::cmp::Ordering {
- // We know we have a number from 0 to 1, so unwrap() here is safe.
- self.0.partial_cmp(&other.0).unwrap()
- }
-}
-
-impl ::std::cmp::Eq for KeyframePercentage {}
-
-impl ToCss for KeyframePercentage {
- fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
- where
- W: Write,
- {
- serialize_percentage(self.0, dest)
- }
-}
-
-impl KeyframePercentage {
- /// Trivially constructs a new `KeyframePercentage`.
- #[inline]
- pub fn new(value: f32) -> KeyframePercentage {
- debug_assert!(value >= 0. && value <= 1.);
- KeyframePercentage(value)
- }
-
- fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<KeyframePercentage, ParseError<'i>> {
- let token = input.next()?.clone();
- match token {
- Token::Ident(ref identifier) if identifier.as_ref().eq_ignore_ascii_case("from") => {
- Ok(KeyframePercentage::new(0.))
- },
- Token::Ident(ref identifier) if identifier.as_ref().eq_ignore_ascii_case("to") => {
- Ok(KeyframePercentage::new(1.))
- },
- Token::Percentage {
- unit_value: percentage,
- ..
- } if percentage >= 0. && percentage <= 1. => Ok(KeyframePercentage::new(percentage)),
- _ => Err(input.new_unexpected_token_error(token)),
- }
- }
-}
-
-/// A keyframes selector is a list of percentages or from/to symbols, which are
-/// converted at parse time to percentages.
-#[derive(Clone, Debug, Eq, PartialEq, ToCss, ToShmem)]
-#[css(comma)]
-pub struct KeyframeSelector(#[css(iterable)] Vec<KeyframePercentage>);
-
-impl KeyframeSelector {
- /// Return the list of percentages this selector contains.
- #[inline]
- pub fn percentages(&self) -> &[KeyframePercentage] {
- &self.0
- }
-
- /// A dummy public function so we can write a unit test for this.
- pub fn new_for_unit_testing(percentages: Vec<KeyframePercentage>) -> KeyframeSelector {
- KeyframeSelector(percentages)
- }
-
- /// Parse a keyframe selector from CSS input.
- pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
- input
- .parse_comma_separated(KeyframePercentage::parse)
- .map(KeyframeSelector)
- }
-}
-
-/// A keyframe.
-#[derive(Debug, ToShmem)]
-pub struct Keyframe {
- /// The selector this keyframe was specified from.
- pub selector: KeyframeSelector,
-
- /// The declaration block that was declared inside this keyframe.
- ///
- /// Note that `!important` rules in keyframes don't apply, but we keep this
- /// `Arc` just for convenience.
- pub block: Arc<Locked<PropertyDeclarationBlock>>,
-
- /// The line and column of the rule's source code.
- pub source_location: SourceLocation,
-}
-
-impl ToCssWithGuard for Keyframe {
- fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
- self.selector.to_css(&mut CssWriter::new(dest))?;
- dest.write_str(" { ")?;
- self.block.read_with(guard).to_css(dest)?;
- dest.write_str(" }")?;
- Ok(())
- }
-}
-
-impl Keyframe {
- /// Parse a CSS keyframe.
- pub fn parse<'i>(
- css: &'i str,
- parent_stylesheet_contents: &StylesheetContents,
- lock: &SharedRwLock,
- ) -> Result<Arc<Locked<Self>>, ParseError<'i>> {
- let url_data = parent_stylesheet_contents.url_data.read();
- let namespaces = parent_stylesheet_contents.namespaces.read();
- let mut context = ParserContext::new(
- parent_stylesheet_contents.origin,
- &url_data,
- Some(CssRuleType::Keyframe),
- ParsingMode::DEFAULT,
- parent_stylesheet_contents.quirks_mode,
- Cow::Borrowed(&*namespaces),
- None,
- None,
- );
- let mut input = ParserInput::new(css);
- let mut input = Parser::new(&mut input);
-
- let mut declarations = SourcePropertyDeclaration::default();
- let mut rule_parser = KeyframeListParser {
- context: &mut context,
- shared_lock: &lock,
- declarations: &mut declarations,
- };
- parse_one_rule(&mut input, &mut rule_parser)
- }
-}
-
-impl DeepCloneWithLock for Keyframe {
- /// Deep clones this Keyframe.
- fn deep_clone_with_lock(
- &self,
- lock: &SharedRwLock,
- guard: &SharedRwLockReadGuard,
- _params: &DeepCloneParams,
- ) -> Keyframe {
- Keyframe {
- selector: self.selector.clone(),
- block: Arc::new(lock.wrap(self.block.read_with(guard).clone())),
- source_location: self.source_location.clone(),
- }
- }
-}
-
-/// A keyframes step value. This can be a synthetised keyframes animation, that
-/// is, one autogenerated from the current computed values, or a list of
-/// declarations to apply.
-///
-/// TODO: Find a better name for this?
-#[derive(Clone, Debug, MallocSizeOf)]
-pub enum KeyframesStepValue {
- /// A step formed by a declaration block specified by the CSS.
- Declarations {
- /// The declaration block per se.
- #[cfg_attr(
- feature = "gecko",
- ignore_malloc_size_of = "XXX: Primary ref, measure if DMD says it's worthwhile"
- )]
- #[cfg_attr(feature = "servo", ignore_malloc_size_of = "Arc")]
- block: Arc<Locked<PropertyDeclarationBlock>>,
- },
- /// A synthetic step computed from the current computed values at the time
- /// of the animation.
- ComputedValues,
-}
-
-/// A single step from a keyframe animation.
-#[derive(Clone, Debug, MallocSizeOf)]
-pub struct KeyframesStep {
- /// The percentage of the animation duration when this step starts.
- pub start_percentage: KeyframePercentage,
- /// Declarations that will determine the final style during the step, or
- /// `ComputedValues` if this is an autogenerated step.
- pub value: KeyframesStepValue,
- /// Whether an animation-timing-function declaration exists in the list of
- /// declarations.
- ///
- /// This is used to know when to override the keyframe animation style.
- pub declared_timing_function: bool,
- /// Whether an animation-composition declaration exists in the list of
- /// declarations.
- ///
- /// This is used to know when to override the keyframe animation style.
- pub declared_composition: bool,
-}
-
-impl KeyframesStep {
- #[inline]
- fn new(
- start_percentage: KeyframePercentage,
- value: KeyframesStepValue,
- guard: &SharedRwLockReadGuard,
- ) -> Self {
- let mut declared_timing_function = false;
- let mut declared_composition = false;
- if let KeyframesStepValue::Declarations { ref block } = value {
- for prop_decl in block.read_with(guard).declarations().iter() {
- match *prop_decl {
- PropertyDeclaration::AnimationTimingFunction(..) => {
- declared_timing_function = true;
- },
- PropertyDeclaration::AnimationComposition(..) => {
- declared_composition = true;
- },
- _ => continue,
- }
- // Don't need to continue the loop if both are found.
- if declared_timing_function && declared_composition {
- break;
- }
- }
- }
-
- KeyframesStep {
- start_percentage,
- value,
- declared_timing_function,
- declared_composition,
- }
- }
-
- /// Return specified PropertyDeclaration.
- #[inline]
- fn get_declared_property<'a>(
- &'a self,
- guard: &'a SharedRwLockReadGuard,
- property: LonghandId,
- ) -> Option<&'a PropertyDeclaration> {
- match self.value {
- KeyframesStepValue::Declarations { ref block } => {
- let guard = block.read_with(guard);
- let (declaration, _) = guard
- .get(PropertyDeclarationId::Longhand(property))
- .unwrap();
- match *declaration {
- PropertyDeclaration::CSSWideKeyword(..) => None,
- // FIXME: Bug 1710735: Support css variable in @keyframes rule.
- PropertyDeclaration::WithVariables(..) => None,
- _ => Some(declaration),
- }
- },
- KeyframesStepValue::ComputedValues => {
- panic!("Shouldn't happen to set this property in missing keyframes")
- },
- }
- }
-
- /// Return specified TransitionTimingFunction if this KeyframesSteps has
- /// 'animation-timing-function'.
- pub fn get_animation_timing_function(
- &self,
- guard: &SharedRwLockReadGuard,
- ) -> Option<SpecifiedTimingFunction> {
- if !self.declared_timing_function {
- return None;
- }
-
- self.get_declared_property(guard, LonghandId::AnimationTimingFunction)
- .map(|decl| {
- match *decl {
- PropertyDeclaration::AnimationTimingFunction(ref value) => {
- // Use the first value
- value.0[0].clone()
- },
- _ => unreachable!("Unexpected PropertyDeclaration"),
- }
- })
- }
-
- /// Return CompositeOperation if this KeyframesSteps has 'animation-composition'.
- pub fn get_animation_composition(
- &self,
- guard: &SharedRwLockReadGuard,
- ) -> Option<SpecifiedComposition> {
- if !self.declared_composition {
- return None;
- }
-
- self.get_declared_property(guard, LonghandId::AnimationComposition)
- .map(|decl| {
- match *decl {
- PropertyDeclaration::AnimationComposition(ref value) => {
- // Use the first value
- value.0[0].clone()
- },
- _ => unreachable!("Unexpected PropertyDeclaration"),
- }
- })
- }
-}
-
-/// This structure represents a list of animation steps computed from the list
-/// of keyframes, in order.
-///
-/// It only takes into account animable properties.
-#[derive(Clone, Debug, MallocSizeOf)]
-pub struct KeyframesAnimation {
- /// The difference steps of the animation.
- pub steps: Vec<KeyframesStep>,
- /// The properties that change in this animation.
- pub properties_changed: LonghandIdSet,
- /// Vendor prefix type the @keyframes has.
- pub vendor_prefix: Option<VendorPrefix>,
-}
-
-/// Get all the animated properties in a keyframes animation.
-fn get_animated_properties(
- keyframes: &[Arc<Locked<Keyframe>>],
- guard: &SharedRwLockReadGuard,
-) -> LonghandIdSet {
- let mut ret = LonghandIdSet::new();
- // NB: declarations are already deduplicated, so we don't have to check for
- // it here.
- for keyframe in keyframes {
- let keyframe = keyframe.read_with(&guard);
- let block = keyframe.block.read_with(guard);
- // CSS Animations spec clearly defines that properties with !important
- // in keyframe rules are invalid and ignored, but it's still ambiguous
- // whether we should drop the !important properties or retain the
- // properties when they are set via CSSOM. So we assume there might
- // be properties with !important in keyframe rules here.
- // See the spec issue https://github.com/w3c/csswg-drafts/issues/1824
- for declaration in block.normal_declaration_iter() {
- let longhand_id = match declaration.id() {
- PropertyDeclarationId::Longhand(id) => id,
- _ => continue,
- };
-
- if longhand_id == LonghandId::Display {
- continue;
- }
-
- if !longhand_id.is_animatable() {
- continue;
- }
-
- ret.insert(longhand_id);
- }
- }
-
- ret
-}
-
-impl KeyframesAnimation {
- /// Create a keyframes animation from a given list of keyframes.
- ///
- /// This will return a keyframe animation with empty steps and
- /// properties_changed if the list of keyframes is empty, or there are no
- /// animated properties obtained from the keyframes.
- ///
- /// Otherwise, this will compute and sort the steps used for the animation,
- /// and return the animation object.
- pub fn from_keyframes(
- keyframes: &[Arc<Locked<Keyframe>>],
- vendor_prefix: Option<VendorPrefix>,
- guard: &SharedRwLockReadGuard,
- ) -> Self {
- let mut result = KeyframesAnimation {
- steps: vec![],
- properties_changed: LonghandIdSet::new(),
- vendor_prefix,
- };
-
- if keyframes.is_empty() {
- return result;
- }
-
- result.properties_changed = get_animated_properties(keyframes, guard);
- if result.properties_changed.is_empty() {
- return result;
- }
-
- for keyframe in keyframes {
- let keyframe = keyframe.read_with(&guard);
- for percentage in keyframe.selector.0.iter() {
- result.steps.push(KeyframesStep::new(
- *percentage,
- KeyframesStepValue::Declarations {
- block: keyframe.block.clone(),
- },
- guard,
- ));
- }
- }
-
- // Sort by the start percentage, so we can easily find a frame.
- result.steps.sort_by_key(|step| step.start_percentage);
-
- // Prepend autogenerated keyframes if appropriate.
- if result.steps[0].start_percentage.0 != 0. {
- result.steps.insert(
- 0,
- KeyframesStep::new(
- KeyframePercentage::new(0.),
- KeyframesStepValue::ComputedValues,
- guard,
- ),
- );
- }
-
- if result.steps.last().unwrap().start_percentage.0 != 1. {
- result.steps.push(KeyframesStep::new(
- KeyframePercentage::new(1.),
- KeyframesStepValue::ComputedValues,
- guard,
- ));
- }
-
- result
- }
-}
-
-/// Parses a keyframes list, like:
-/// 0%, 50% {
-/// width: 50%;
-/// }
-///
-/// 40%, 60%, 100% {
-/// width: 100%;
-/// }
-struct KeyframeListParser<'a, 'b> {
- context: &'a mut ParserContext<'b>,
- shared_lock: &'a SharedRwLock,
- declarations: &'a mut SourcePropertyDeclaration,
-}
-
-/// Parses a keyframe list from CSS input.
-pub fn parse_keyframe_list<'a>(
- context: &mut ParserContext<'a>,
- input: &mut Parser,
- shared_lock: &SharedRwLock,
-) -> Vec<Arc<Locked<Keyframe>>> {
- let mut declarations = SourcePropertyDeclaration::default();
- let mut parser = KeyframeListParser {
- context,
- shared_lock,
- declarations: &mut declarations,
- };
- RuleBodyParser::new(input, &mut parser)
- .filter_map(Result::ok)
- .collect()
-}
-
-impl<'a, 'b, 'i> AtRuleParser<'i> for KeyframeListParser<'a, 'b> {
- type Prelude = ();
- type AtRule = Arc<Locked<Keyframe>>;
- type Error = StyleParseErrorKind<'i>;
-}
-
-impl<'a, 'b, 'i> DeclarationParser<'i> for KeyframeListParser<'a, 'b> {
- type Declaration = Arc<Locked<Keyframe>>;
- type Error = StyleParseErrorKind<'i>;
-}
-
-impl<'a, 'b, 'i> QualifiedRuleParser<'i> for KeyframeListParser<'a, 'b> {
- type Prelude = KeyframeSelector;
- type QualifiedRule = Arc<Locked<Keyframe>>;
- type Error = StyleParseErrorKind<'i>;
-
- fn parse_prelude<'t>(
- &mut self,
- input: &mut Parser<'i, 't>,
- ) -> Result<Self::Prelude, ParseError<'i>> {
- let start_position = input.position();
- KeyframeSelector::parse(input).map_err(|e| {
- let location = e.location;
- let error = ContextualParseError::InvalidKeyframeRule(
- input.slice_from(start_position),
- e.clone(),
- );
- self.context.log_css_error(location, error);
- e
- })
- }
-
- fn parse_block<'t>(
- &mut self,
- selector: Self::Prelude,
- start: &ParserState,
- input: &mut Parser<'i, 't>,
- ) -> Result<Self::QualifiedRule, ParseError<'i>> {
- let mut block = PropertyDeclarationBlock::new();
- let declarations = &mut self.declarations;
- self.context
- .nest_for_rule(CssRuleType::Keyframe, |context| {
- let mut parser = KeyframeDeclarationParser {
- context: &context,
- declarations,
- };
- let mut iter = RuleBodyParser::new(input, &mut parser);
- while let Some(declaration) = iter.next() {
- match declaration {
- Ok(()) => {
- block.extend(iter.parser.declarations.drain(), Importance::Normal);
- },
- Err((error, slice)) => {
- iter.parser.declarations.clear();
- let location = error.location;
- let error =
- ContextualParseError::UnsupportedKeyframePropertyDeclaration(
- slice, error,
- );
- context.log_css_error(location, error);
- },
- }
- // `parse_important` is not called here, `!important` is not allowed in keyframe blocks.
- }
- });
- Ok(Arc::new(self.shared_lock.wrap(Keyframe {
- selector,
- block: Arc::new(self.shared_lock.wrap(block)),
- source_location: start.source_location(),
- })))
- }
-}
-
-impl<'a, 'b, 'i> RuleBodyItemParser<'i, Arc<Locked<Keyframe>>, StyleParseErrorKind<'i>>
- for KeyframeListParser<'a, 'b>
-{
- fn parse_qualified(&self) -> bool {
- true
- }
- fn parse_declarations(&self) -> bool {
- false
- }
-}
-
-struct KeyframeDeclarationParser<'a, 'b: 'a> {
- context: &'a ParserContext<'b>,
- declarations: &'a mut SourcePropertyDeclaration,
-}
-
-/// Default methods reject all at rules.
-impl<'a, 'b, 'i> AtRuleParser<'i> for KeyframeDeclarationParser<'a, 'b> {
- type Prelude = ();
- type AtRule = ();
- type Error = StyleParseErrorKind<'i>;
-}
-
-impl<'a, 'b, 'i> QualifiedRuleParser<'i> for KeyframeDeclarationParser<'a, 'b> {
- type Prelude = ();
- type QualifiedRule = ();
- type Error = StyleParseErrorKind<'i>;
-}
-
-impl<'a, 'b, 'i> DeclarationParser<'i> for KeyframeDeclarationParser<'a, 'b> {
- type Declaration = ();
- type Error = StyleParseErrorKind<'i>;
-
- fn parse_value<'t>(
- &mut self,
- name: CowRcStr<'i>,
- input: &mut Parser<'i, 't>,
- ) -> Result<(), ParseError<'i>> {
- let id = match PropertyId::parse(&name, self.context) {
- Ok(id) => id,
- Err(()) => {
- return Err(input.new_custom_error(StyleParseErrorKind::UnknownProperty(name)));
- },
- };
-
- // TODO(emilio): Shouldn't this use parse_entirely?
- PropertyDeclaration::parse_into(self.declarations, id, self.context, input)?;
-
- // In case there is still unparsed text in the declaration, we should
- // roll back.
- input.expect_exhausted()?;
-
- Ok(())
- }
-}
-
-impl<'a, 'b, 'i> RuleBodyItemParser<'i, (), StyleParseErrorKind<'i>>
- for KeyframeDeclarationParser<'a, 'b>
-{
- fn parse_qualified(&self) -> bool {
- false
- }
- fn parse_declarations(&self) -> bool {
- true
- }
-}
diff --git a/components/style/stylesheets/layer_rule.rs b/components/style/stylesheets/layer_rule.rs
deleted file mode 100644
index 3ebe6bb34f8..00000000000
--- a/components/style/stylesheets/layer_rule.rs
+++ /dev/null
@@ -1,228 +0,0 @@
-/* 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/. */
-
-//! A [`@layer`][layer] rule.
-//!
-//! [layer]: https://drafts.csswg.org/css-cascade-5/#layering
-
-use crate::parser::{Parse, ParserContext};
-use crate::shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked};
-use crate::shared_lock::{SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard};
-use crate::values::AtomIdent;
-
-use super::CssRules;
-
-use cssparser::{Parser, SourceLocation, Token};
-use servo_arc::Arc;
-use smallvec::SmallVec;
-use std::fmt::{self, Write};
-use style_traits::{CssWriter, ParseError, ToCss};
-
-/// The order of a given layer. We use 16 bits so that we can pack LayerOrder
-/// and CascadeLevel in a single 32-bit struct. If we need more bits we can go
-/// back to packing CascadeLevel in a single byte as we did before.
-#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq, PartialOrd, Ord)]
-pub struct LayerOrder(u16);
-
-impl LayerOrder {
- /// The order of the root layer.
- pub const fn root() -> Self {
- Self(std::u16::MAX - 1)
- }
-
- /// The order of the style attribute layer.
- pub const fn style_attribute() -> Self {
- Self(std::u16::MAX)
- }
-
- /// Returns whether this layer is for the style attribute, which behaves
- /// differently in terms of !important, see
- /// https://github.com/w3c/csswg-drafts/issues/6872
- ///
- /// (This is a bit silly, mind-you, but it's needed so that revert-layer
- /// behaves correctly).
- #[inline]
- pub fn is_style_attribute_layer(&self) -> bool {
- *self == Self::style_attribute()
- }
-
- /// The first cascade layer order.
- pub const fn first() -> Self {
- Self(0)
- }
-
- /// Increment the cascade layer order.
- #[inline]
- pub fn inc(&mut self) {
- if self.0 != std::u16::MAX - 1 {
- self.0 += 1;
- }
- }
-}
-
-/// A `<layer-name>`: https://drafts.csswg.org/css-cascade-5/#typedef-layer-name
-#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToShmem)]
-pub struct LayerName(pub SmallVec<[AtomIdent; 1]>);
-
-impl LayerName {
- /// Returns an empty layer name (which isn't a valid final state, so caller
- /// is responsible to fill up the name before use).
- pub fn new_empty() -> Self {
- Self(Default::default())
- }
-
- /// Returns a synthesized name for an anonymous layer.
- pub fn new_anonymous() -> Self {
- use std::sync::atomic::{AtomicUsize, Ordering};
- static NEXT_ANONYMOUS_LAYER_NAME: AtomicUsize = AtomicUsize::new(0);
-
- let mut name = SmallVec::new();
- let next_id = NEXT_ANONYMOUS_LAYER_NAME.fetch_add(1, Ordering::Relaxed);
- // The parens don't _technically_ prevent conflicts with authors, as
- // authors could write escaped parens as part of the identifier, I
- // think, but highly reduces the possibility.
- name.push(AtomIdent::from(&*format!("-moz-anon-layer({})", next_id)));
-
- LayerName(name)
- }
-
- /// Returns the names of the layers. That is, for a layer like `foo.bar`,
- /// it'd return [foo, bar].
- pub fn layer_names(&self) -> &[AtomIdent] {
- &self.0
- }
-}
-
-impl Parse for LayerName {
- fn parse<'i, 't>(
- _: &ParserContext,
- input: &mut Parser<'i, 't>,
- ) -> Result<Self, ParseError<'i>> {
- let mut result = SmallVec::new();
- result.push(AtomIdent::from(&**input.expect_ident()?));
- loop {
- let next_name = input.try_parse(|input| -> Result<AtomIdent, ParseError<'i>> {
- match input.next_including_whitespace()? {
- Token::Delim('.') => {},
- other => {
- let t = other.clone();
- return Err(input.new_unexpected_token_error(t));
- },
- }
-
- let name = match input.next_including_whitespace()? {
- Token::Ident(ref ident) => ident,
- other => {
- let t = other.clone();
- return Err(input.new_unexpected_token_error(t));
- },
- };
-
- Ok(AtomIdent::from(&**name))
- });
-
- match next_name {
- Ok(name) => result.push(name),
- Err(..) => break,
- }
- }
- Ok(LayerName(result))
- }
-}
-
-impl ToCss for LayerName {
- fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
- where
- W: Write,
- {
- let mut first = true;
- for name in self.0.iter() {
- if !first {
- dest.write_char('.')?;
- }
- first = false;
- name.to_css(dest)?;
- }
- Ok(())
- }
-}
-
-#[derive(Debug, ToShmem)]
-/// A block `@layer <name>? { ... }`
-/// https://drafts.csswg.org/css-cascade-5/#layer-block
-pub struct LayerBlockRule {
- /// The layer name, or `None` if anonymous.
- pub name: Option<LayerName>,
- /// The nested rules.
- pub rules: Arc<Locked<CssRules>>,
- /// The source position where this rule was found.
- pub source_location: SourceLocation,
-}
-
-impl ToCssWithGuard for LayerBlockRule {
- fn to_css(
- &self,
- guard: &SharedRwLockReadGuard,
- dest: &mut crate::str::CssStringWriter,
- ) -> fmt::Result {
- dest.write_str("@layer")?;
- if let Some(ref name) = self.name {
- dest.write_char(' ')?;
- name.to_css(&mut CssWriter::new(dest))?;
- }
- self.rules.read_with(guard).to_css_block(guard, dest)
- }
-}
-
-impl DeepCloneWithLock for LayerBlockRule {
- fn deep_clone_with_lock(
- &self,
- lock: &SharedRwLock,
- guard: &SharedRwLockReadGuard,
- params: &DeepCloneParams,
- ) -> Self {
- Self {
- name: self.name.clone(),
- rules: Arc::new(
- lock.wrap(
- self.rules
- .read_with(guard)
- .deep_clone_with_lock(lock, guard, params),
- ),
- ),
- source_location: self.source_location.clone(),
- }
- }
-}
-
-/// A statement `@layer <name>, <name>, <name>;`
-///
-/// https://drafts.csswg.org/css-cascade-5/#layer-empty
-#[derive(Clone, Debug, ToShmem)]
-pub struct LayerStatementRule {
- /// The list of layers to sort.
- pub names: Vec<LayerName>,
- /// The source position where this rule was found.
- pub source_location: SourceLocation,
-}
-
-impl ToCssWithGuard for LayerStatementRule {
- fn to_css(
- &self,
- _: &SharedRwLockReadGuard,
- dest: &mut crate::str::CssStringWriter,
- ) -> fmt::Result {
- let mut writer = CssWriter::new(dest);
- writer.write_str("@layer ")?;
- let mut first = true;
- for name in &*self.names {
- if !first {
- writer.write_str(", ")?;
- }
- first = false;
- name.to_css(&mut writer)?;
- }
- writer.write_char(';')
- }
-}
diff --git a/components/style/stylesheets/loader.rs b/components/style/stylesheets/loader.rs
deleted file mode 100644
index f987cf95972..00000000000
--- a/components/style/stylesheets/loader.rs
+++ /dev/null
@@ -1,31 +0,0 @@
-/* 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/. */
-
-//! The stylesheet loader is the abstraction used to trigger network requests
-//! for `@import` rules.
-
-use crate::media_queries::MediaList;
-use crate::parser::ParserContext;
-use crate::shared_lock::{Locked, SharedRwLock};
-use crate::stylesheets::import_rule::{ImportLayer, ImportRule, ImportSupportsCondition};
-use crate::values::CssUrl;
-use cssparser::SourceLocation;
-use servo_arc::Arc;
-
-/// The stylesheet loader is the abstraction used to trigger network requests
-/// for `@import` rules.
-pub trait StylesheetLoader {
- /// Request a stylesheet after parsing a given `@import` rule, and return
- /// the constructed `@import` rule.
- fn request_stylesheet(
- &self,
- url: CssUrl,
- location: SourceLocation,
- context: &ParserContext,
- lock: &SharedRwLock,
- media: Arc<Locked<MediaList>>,
- supports: Option<ImportSupportsCondition>,
- layer: ImportLayer,
- ) -> Arc<Locked<ImportRule>>;
-}
diff --git a/components/style/stylesheets/media_rule.rs b/components/style/stylesheets/media_rule.rs
deleted file mode 100644
index cde60a16bf7..00000000000
--- a/components/style/stylesheets/media_rule.rs
+++ /dev/null
@@ -1,71 +0,0 @@
-/* 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/. */
-
-//! An [`@media`][media] rule.
-//!
-//! [media]: https://drafts.csswg.org/css-conditional/#at-ruledef-media
-
-use crate::media_queries::MediaList;
-use crate::shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked};
-use crate::shared_lock::{SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard};
-use crate::str::CssStringWriter;
-use crate::stylesheets::CssRules;
-use cssparser::SourceLocation;
-#[cfg(feature = "gecko")]
-use malloc_size_of::{MallocSizeOfOps, MallocUnconditionalShallowSizeOf};
-use servo_arc::Arc;
-use std::fmt::{self, Write};
-use style_traits::{CssWriter, ToCss};
-
-/// An [`@media`][media] rule.
-///
-/// [media]: https://drafts.csswg.org/css-conditional/#at-ruledef-media
-#[derive(Debug, ToShmem)]
-pub struct MediaRule {
- /// The list of media queries used by this media rule.
- pub media_queries: Arc<Locked<MediaList>>,
- /// The nested rules to this media rule.
- pub rules: Arc<Locked<CssRules>>,
- /// The source position where this media rule was found.
- pub source_location: SourceLocation,
-}
-
-impl MediaRule {
- /// Measure heap usage.
- #[cfg(feature = "gecko")]
- pub fn size_of(&self, guard: &SharedRwLockReadGuard, ops: &mut MallocSizeOfOps) -> usize {
- // Measurement of other fields may be added later.
- self.rules.unconditional_shallow_size_of(ops) +
- self.rules.read_with(guard).size_of(guard, ops)
- }
-}
-
-impl ToCssWithGuard for MediaRule {
- // Serialization of MediaRule is not specced.
- // https://drafts.csswg.org/cssom/#serialize-a-css-rule CSSMediaRule
- fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
- dest.write_str("@media ")?;
- self.media_queries
- .read_with(guard)
- .to_css(&mut CssWriter::new(dest))?;
- self.rules.read_with(guard).to_css_block(guard, dest)
- }
-}
-
-impl DeepCloneWithLock for MediaRule {
- fn deep_clone_with_lock(
- &self,
- lock: &SharedRwLock,
- guard: &SharedRwLockReadGuard,
- params: &DeepCloneParams,
- ) -> Self {
- let media_queries = self.media_queries.read_with(guard);
- let rules = self.rules.read_with(guard);
- MediaRule {
- media_queries: Arc::new(lock.wrap(media_queries.clone())),
- rules: Arc::new(lock.wrap(rules.deep_clone_with_lock(lock, guard, params))),
- source_location: self.source_location.clone(),
- }
- }
-}
diff --git a/components/style/stylesheets/mod.rs b/components/style/stylesheets/mod.rs
deleted file mode 100644
index 85d6619d135..00000000000
--- a/components/style/stylesheets/mod.rs
+++ /dev/null
@@ -1,582 +0,0 @@
-/* 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/. */
-
-//! Style sheets and their CSS rules.
-
-pub mod container_rule;
-mod counter_style_rule;
-mod document_rule;
-mod font_face_rule;
-pub mod font_feature_values_rule;
-pub mod font_palette_values_rule;
-pub mod import_rule;
-pub mod keyframes_rule;
-pub mod layer_rule;
-mod loader;
-mod media_rule;
-mod namespace_rule;
-pub mod origin;
-mod page_rule;
-mod property_rule;
-mod rule_list;
-mod rule_parser;
-mod rules_iterator;
-mod style_rule;
-mod stylesheet;
-pub mod supports_rule;
-
-#[cfg(feature = "gecko")]
-use crate::gecko_bindings::sugar::refptr::RefCounted;
-#[cfg(feature = "gecko")]
-use crate::gecko_bindings::{bindings, structs};
-use crate::parser::ParserContext;
-use crate::shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked};
-use crate::shared_lock::{SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard};
-use crate::str::CssStringWriter;
-use cssparser::{parse_one_rule, Parser, ParserInput};
-#[cfg(feature = "gecko")]
-use malloc_size_of::{MallocSizeOfOps, MallocUnconditionalShallowSizeOf};
-use servo_arc::Arc;
-use std::borrow::Cow;
-use std::fmt;
-#[cfg(feature = "gecko")]
-use std::mem::{self, ManuallyDrop};
-use style_traits::ParsingMode;
-use to_shmem::{self, SharedMemoryBuilder, ToShmem};
-
-pub use self::container_rule::ContainerRule;
-pub use self::counter_style_rule::CounterStyleRule;
-pub use self::document_rule::DocumentRule;
-pub use self::font_face_rule::FontFaceRule;
-pub use self::font_feature_values_rule::FontFeatureValuesRule;
-pub use self::font_palette_values_rule::FontPaletteValuesRule;
-pub use self::import_rule::ImportRule;
-pub use self::keyframes_rule::KeyframesRule;
-pub use self::layer_rule::{LayerBlockRule, LayerStatementRule};
-pub use self::loader::StylesheetLoader;
-pub use self::media_rule::MediaRule;
-pub use self::namespace_rule::NamespaceRule;
-pub use self::origin::{Origin, OriginSet, OriginSetIterator, PerOrigin, PerOriginIter};
-pub use self::page_rule::{PageRule, PageSelector, PageSelectors};
-pub use self::property_rule::PropertyRule;
-pub use self::rule_list::{CssRules, CssRulesHelpers};
-pub use self::rule_parser::{InsertRuleContext, State, TopLevelRuleParser};
-pub use self::rules_iterator::{AllRules, EffectiveRules};
-pub use self::rules_iterator::{
- EffectiveRulesIterator, NestedRuleIterationCondition, RulesIterator,
-};
-pub use self::style_rule::StyleRule;
-pub use self::stylesheet::{AllowImportRules, SanitizationData, SanitizationKind};
-pub use self::stylesheet::{DocumentStyleSheet, Namespaces, Stylesheet};
-pub use self::stylesheet::{StylesheetContents, StylesheetInDocument, UserAgentStylesheets};
-pub use self::supports_rule::SupportsRule;
-
-/// The CORS mode used for a CSS load.
-#[repr(u8)]
-#[derive(Clone, Copy, Debug, Eq, PartialEq, ToShmem)]
-pub enum CorsMode {
- /// No CORS mode, so cross-origin loads can be done.
- None,
- /// Anonymous CORS request.
- Anonymous,
-}
-
-/// Extra data that the backend may need to resolve url values.
-///
-/// If the usize's lowest bit is 0, then this is a strong reference to a
-/// structs::URLExtraData object.
-///
-/// Otherwise, shifting the usize's bits the right by one gives the
-/// UserAgentStyleSheetID value corresponding to the style sheet whose
-/// URLExtraData this is, which is stored in URLExtraData_sShared. We don't
-/// hold a strong reference to that object from here, but we rely on that
-/// array's objects being held alive until shutdown.
-///
-/// We use this packed representation rather than an enum so that
-/// `from_ptr_ref` can work.
-#[cfg(feature = "gecko")]
-#[derive(PartialEq)]
-#[repr(C)]
-pub struct UrlExtraData(usize);
-
-/// Extra data that the backend may need to resolve url values.
-#[cfg(feature = "servo")]
-#[derive(Clone, Debug, Eq, PartialEq)]
-pub struct UrlExtraData(pub Arc<::url::Url>);
-
-#[cfg(feature = "servo")]
-impl UrlExtraData {
- /// True if this URL scheme is chrome.
- pub fn chrome_rules_enabled(&self) -> bool {
- self.0.scheme() == "chrome"
- }
-
- /// Get the interior Url as a string.
- pub fn as_str(&self) -> &str {
- self.0.as_str()
- }
-}
-
-#[cfg(feature = "servo")]
-impl From<::url::Url> for UrlExtraData {
- fn from(url: ::url::Url) -> Self {
- Self(Arc::new(url))
- }
-}
-
-#[cfg(not(feature = "gecko"))]
-impl ToShmem for UrlExtraData {
- fn to_shmem(&self, _builder: &mut SharedMemoryBuilder) -> to_shmem::Result<Self> {
- unimplemented!("If servo wants to share stylesheets across processes, ToShmem for Url must be implemented");
- }
-}
-
-#[cfg(feature = "gecko")]
-impl Clone for UrlExtraData {
- fn clone(&self) -> UrlExtraData {
- UrlExtraData::new(self.ptr())
- }
-}
-
-#[cfg(feature = "gecko")]
-impl Drop for UrlExtraData {
- fn drop(&mut self) {
- // No need to release when we have an index into URLExtraData_sShared.
- if self.0 & 1 == 0 {
- unsafe {
- self.as_ref().release();
- }
- }
- }
-}
-
-#[cfg(feature = "gecko")]
-impl ToShmem for UrlExtraData {
- fn to_shmem(&self, _builder: &mut SharedMemoryBuilder) -> to_shmem::Result<Self> {
- if self.0 & 1 == 0 {
- let shared_extra_datas = unsafe { &structs::URLExtraData_sShared };
- let self_ptr = self.as_ref() as *const _ as *mut _;
- let sheet_id = shared_extra_datas
- .iter()
- .position(|r| r.mRawPtr == self_ptr);
- let sheet_id = match sheet_id {
- Some(id) => id,
- None => {
- return Err(String::from(
- "ToShmem failed for UrlExtraData: expected sheet's URLExtraData to be in \
- URLExtraData::sShared",
- ));
- },
- };
- Ok(ManuallyDrop::new(UrlExtraData((sheet_id << 1) | 1)))
- } else {
- Ok(ManuallyDrop::new(UrlExtraData(self.0)))
- }
- }
-}
-
-#[cfg(feature = "gecko")]
-impl UrlExtraData {
- /// Create a new UrlExtraData wrapping a pointer to the specified Gecko
- /// URLExtraData object.
- pub fn new(ptr: *mut structs::URLExtraData) -> UrlExtraData {
- unsafe {
- (*ptr).addref();
- }
- UrlExtraData(ptr as usize)
- }
-
- /// True if this URL scheme is chrome.
- #[inline]
- pub fn chrome_rules_enabled(&self) -> bool {
- self.as_ref().mChromeRulesEnabled
- }
-
- /// Create a reference to this `UrlExtraData` from a reference to pointer.
- ///
- /// The pointer must be valid and non null.
- ///
- /// This method doesn't touch refcount.
- #[inline]
- pub unsafe fn from_ptr_ref(ptr: &*mut structs::URLExtraData) -> &Self {
- mem::transmute(ptr)
- }
-
- /// Returns a pointer to the Gecko URLExtraData object.
- pub fn ptr(&self) -> *mut structs::URLExtraData {
- if self.0 & 1 == 0 {
- self.0 as *mut structs::URLExtraData
- } else {
- unsafe {
- let sheet_id = self.0 >> 1;
- structs::URLExtraData_sShared[sheet_id].mRawPtr
- }
- }
- }
-
- fn as_ref(&self) -> &structs::URLExtraData {
- unsafe { &*(self.ptr() as *const structs::URLExtraData) }
- }
-}
-
-#[cfg(feature = "gecko")]
-impl fmt::Debug for UrlExtraData {
- fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- macro_rules! define_debug_struct {
- ($struct_name:ident, $gecko_class:ident, $debug_fn:ident) => {
- struct $struct_name(*mut structs::$gecko_class);
- impl fmt::Debug for $struct_name {
- fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- use nsstring::nsCString;
- let mut spec = nsCString::new();
- unsafe {
- bindings::$debug_fn(self.0, &mut spec);
- }
- spec.fmt(formatter)
- }
- }
- };
- }
-
- define_debug_struct!(DebugURI, nsIURI, Gecko_nsIURI_Debug);
- define_debug_struct!(
- DebugReferrerInfo,
- nsIReferrerInfo,
- Gecko_nsIReferrerInfo_Debug
- );
-
- formatter
- .debug_struct("URLExtraData")
- .field("chrome_rules_enabled", &self.chrome_rules_enabled())
- .field("base", &DebugURI(self.as_ref().mBaseURI.raw()))
- .field(
- "referrer",
- &DebugReferrerInfo(self.as_ref().mReferrerInfo.raw()),
- )
- .finish()
- }
-}
-
-// XXX We probably need to figure out whether we should mark Eq here.
-// It is currently marked so because properties::UnparsedValue wants Eq.
-#[cfg(feature = "gecko")]
-impl Eq for UrlExtraData {}
-
-/// A CSS rule.
-///
-/// TODO(emilio): Lots of spec links should be around.
-#[derive(Clone, Debug, ToShmem)]
-#[allow(missing_docs)]
-pub enum CssRule {
- // No Charset here, CSSCharsetRule has been removed from CSSOM
- // https://drafts.csswg.org/cssom/#changes-from-5-december-2013
- Namespace(Arc<NamespaceRule>),
- Import(Arc<Locked<ImportRule>>),
- Style(Arc<Locked<StyleRule>>),
- Media(Arc<MediaRule>),
- Container(Arc<ContainerRule>),
- FontFace(Arc<Locked<FontFaceRule>>),
- FontFeatureValues(Arc<FontFeatureValuesRule>),
- FontPaletteValues(Arc<FontPaletteValuesRule>),
- CounterStyle(Arc<Locked<CounterStyleRule>>),
- Keyframes(Arc<Locked<KeyframesRule>>),
- Supports(Arc<SupportsRule>),
- Page(Arc<Locked<PageRule>>),
- Property(Arc<PropertyRule>),
- Document(Arc<DocumentRule>),
- LayerBlock(Arc<LayerBlockRule>),
- LayerStatement(Arc<LayerStatementRule>),
-}
-
-impl CssRule {
- /// Measure heap usage.
- #[cfg(feature = "gecko")]
- fn size_of(&self, guard: &SharedRwLockReadGuard, ops: &mut MallocSizeOfOps) -> usize {
- match *self {
- // Not all fields are currently fully measured. Extra measurement
- // may be added later.
- CssRule::Namespace(_) => 0,
-
- // We don't need to measure ImportRule::stylesheet because we measure
- // it on the C++ side in the child list of the ServoStyleSheet.
- CssRule::Import(_) => 0,
-
- CssRule::Style(ref lock) => {
- lock.unconditional_shallow_size_of(ops) + lock.read_with(guard).size_of(guard, ops)
- },
- CssRule::Media(ref arc) => {
- arc.unconditional_shallow_size_of(ops) + arc.size_of(guard, ops)
- },
- CssRule::Container(ref arc) => {
- arc.unconditional_shallow_size_of(ops) + arc.size_of(guard, ops)
- },
- CssRule::FontFace(_) => 0,
- CssRule::FontFeatureValues(_) => 0,
- CssRule::FontPaletteValues(_) => 0,
- CssRule::CounterStyle(_) => 0,
- CssRule::Keyframes(_) => 0,
- CssRule::Supports(ref arc) => {
- arc.unconditional_shallow_size_of(ops) + arc.size_of(guard, ops)
- },
- CssRule::Page(ref lock) => {
- lock.unconditional_shallow_size_of(ops) + lock.read_with(guard).size_of(guard, ops)
- },
- CssRule::Property(ref rule) => {
- rule.unconditional_shallow_size_of(ops) + rule.size_of(guard, ops)
- },
- CssRule::Document(ref arc) => {
- arc.unconditional_shallow_size_of(ops) + arc.size_of(guard, ops)
- },
- // TODO(emilio): Add memory reporting for these rules.
- CssRule::LayerBlock(_) | CssRule::LayerStatement(_) => 0,
- }
- }
-}
-
-/// https://drafts.csswg.org/cssom-1/#dom-cssrule-type
-#[allow(missing_docs)]
-#[derive(Clone, Copy, Debug, Eq, FromPrimitive, PartialEq)]
-#[repr(u8)]
-pub enum CssRuleType {
- // https://drafts.csswg.org/cssom/#the-cssrule-interface
- Style = 1,
- // Charset = 2, // Historical
- Import = 3,
- Media = 4,
- FontFace = 5,
- Page = 6,
- // https://drafts.csswg.org/css-animations-1/#interface-cssrule-idl
- Keyframes = 7,
- Keyframe = 8,
- // https://drafts.csswg.org/cssom/#the-cssrule-interface
- // Margin = 9, // Not implemented yet.
- Namespace = 10,
- // https://drafts.csswg.org/css-counter-styles-3/#extentions-to-cssrule-interface
- CounterStyle = 11,
- // https://drafts.csswg.org/css-conditional-3/#extentions-to-cssrule-interface
- Supports = 12,
- // https://www.w3.org/TR/2012/WD-css3-conditional-20120911/#extentions-to-cssrule-interface
- Document = 13,
- // https://drafts.csswg.org/css-fonts/#om-fontfeaturevalues
- FontFeatureValues = 14,
- // After viewport, all rules should return 0 from the API, but we still need
- // a constant somewhere.
- LayerBlock = 16,
- LayerStatement = 17,
- Container = 18,
- FontPaletteValues = 19,
- // 20 is an arbitrary number to use for Property.
- Property = 20,
-}
-
-impl CssRuleType {
- /// Returns a bit that identifies this rule type.
- #[inline]
- pub const fn bit(self) -> u32 {
- 1 << self as u32
- }
-}
-
-/// Set of rule types.
-#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
-pub struct CssRuleTypes(u32);
-
-impl From<CssRuleType> for CssRuleTypes {
- fn from(ty: CssRuleType) -> Self {
- Self(ty.bit())
- }
-}
-
-impl CssRuleTypes {
- /// Returns whether the rule is in the current set.
- #[inline]
- pub fn contains(self, ty: CssRuleType) -> bool {
- self.0 & ty.bit() != 0
- }
-
- /// Returns all the rules specified in the set.
- pub fn bits(self) -> u32 {
- self.0
- }
-
- /// Inserts a rule type into the set.
- #[inline]
- pub fn insert(&mut self, ty: CssRuleType) {
- self.0 |= ty.bit()
- }
-}
-
-#[allow(missing_docs)]
-pub enum RulesMutateError {
- Syntax,
- IndexSize,
- HierarchyRequest,
- InvalidState,
-}
-
-impl CssRule {
- /// Returns the CSSOM rule type of this rule.
- pub fn rule_type(&self) -> CssRuleType {
- match *self {
- CssRule::Style(_) => CssRuleType::Style,
- CssRule::Import(_) => CssRuleType::Import,
- CssRule::Media(_) => CssRuleType::Media,
- CssRule::FontFace(_) => CssRuleType::FontFace,
- CssRule::FontFeatureValues(_) => CssRuleType::FontFeatureValues,
- CssRule::FontPaletteValues(_) => CssRuleType::FontPaletteValues,
- CssRule::CounterStyle(_) => CssRuleType::CounterStyle,
- CssRule::Keyframes(_) => CssRuleType::Keyframes,
- CssRule::Namespace(_) => CssRuleType::Namespace,
- CssRule::Supports(_) => CssRuleType::Supports,
- CssRule::Page(_) => CssRuleType::Page,
- CssRule::Property(_) => CssRuleType::Property,
- CssRule::Document(_) => CssRuleType::Document,
- CssRule::LayerBlock(_) => CssRuleType::LayerBlock,
- CssRule::LayerStatement(_) => CssRuleType::LayerStatement,
- CssRule::Container(_) => CssRuleType::Container,
- }
- }
-
- /// Parse a CSS rule.
- ///
- /// Returns a parsed CSS rule and the final state of the parser.
- ///
- /// Input state is None for a nested rule
- pub fn parse(
- css: &str,
- insert_rule_context: InsertRuleContext,
- parent_stylesheet_contents: &StylesheetContents,
- shared_lock: &SharedRwLock,
- state: State,
- loader: Option<&dyn StylesheetLoader>,
- allow_import_rules: AllowImportRules,
- ) -> Result<Self, RulesMutateError> {
- let url_data = parent_stylesheet_contents.url_data.read();
- let namespaces = parent_stylesheet_contents.namespaces.read();
- let context = ParserContext::new(
- parent_stylesheet_contents.origin,
- &url_data,
- None,
- ParsingMode::DEFAULT,
- parent_stylesheet_contents.quirks_mode,
- Cow::Borrowed(&*namespaces),
- None,
- None,
- );
-
- let mut input = ParserInput::new(css);
- let mut input = Parser::new(&mut input);
-
- // nested rules are in the body state
- let mut rule_parser = TopLevelRuleParser {
- context,
- shared_lock: &shared_lock,
- loader,
- state,
- dom_error: None,
- insert_rule_context: Some(insert_rule_context),
- allow_import_rules,
- declaration_parser_state: Default::default(),
- rules: Default::default(),
- };
-
- match parse_one_rule(&mut input, &mut rule_parser) {
- Ok(_) => Ok(rule_parser.rules.pop().unwrap()),
- Err(_) => Err(rule_parser.dom_error.unwrap_or(RulesMutateError::Syntax)),
- }
- }
-}
-
-impl DeepCloneWithLock for CssRule {
- /// Deep clones this CssRule.
- fn deep_clone_with_lock(
- &self,
- lock: &SharedRwLock,
- guard: &SharedRwLockReadGuard,
- params: &DeepCloneParams,
- ) -> CssRule {
- match *self {
- CssRule::Namespace(ref arc) => CssRule::Namespace(arc.clone()),
- CssRule::Import(ref arc) => {
- let rule = arc
- .read_with(guard)
- .deep_clone_with_lock(lock, guard, params);
- CssRule::Import(Arc::new(lock.wrap(rule)))
- },
- CssRule::Style(ref arc) => {
- let rule = arc.read_with(guard);
- CssRule::Style(Arc::new(
- lock.wrap(rule.deep_clone_with_lock(lock, guard, params)),
- ))
- },
- CssRule::Container(ref arc) => {
- CssRule::Container(Arc::new(arc.deep_clone_with_lock(lock, guard, params)))
- },
- CssRule::Media(ref arc) => {
- CssRule::Media(Arc::new(arc.deep_clone_with_lock(lock, guard, params)))
- },
- CssRule::FontFace(ref arc) => {
- let rule = arc.read_with(guard);
- CssRule::FontFace(Arc::new(lock.wrap(rule.clone())))
- },
- CssRule::FontFeatureValues(ref arc) => CssRule::FontFeatureValues(arc.clone()),
- CssRule::FontPaletteValues(ref arc) => CssRule::FontPaletteValues(arc.clone()),
- CssRule::CounterStyle(ref arc) => {
- let rule = arc.read_with(guard);
- CssRule::CounterStyle(Arc::new(lock.wrap(rule.clone())))
- },
- CssRule::Keyframes(ref arc) => {
- let rule = arc.read_with(guard);
- CssRule::Keyframes(Arc::new(
- lock.wrap(rule.deep_clone_with_lock(lock, guard, params)),
- ))
- },
- CssRule::Supports(ref arc) => {
- CssRule::Supports(Arc::new(arc.deep_clone_with_lock(lock, guard, params)))
- },
- CssRule::Page(ref arc) => {
- let rule = arc.read_with(guard);
- CssRule::Page(Arc::new(
- lock.wrap(rule.deep_clone_with_lock(lock, guard, params)),
- ))
- },
- CssRule::Property(ref arc) => {
- // @property rules are immutable, so we don't need any of the `Locked`
- // shenanigans, actually, and can just share the rule.
- CssRule::Property(arc.clone())
- },
- CssRule::Document(ref arc) => {
- CssRule::Document(Arc::new(arc.deep_clone_with_lock(lock, guard, params)))
- },
- CssRule::LayerStatement(ref arc) => CssRule::LayerStatement(arc.clone()),
- CssRule::LayerBlock(ref arc) => {
- CssRule::LayerBlock(Arc::new(arc.deep_clone_with_lock(lock, guard, params)))
- },
- }
- }
-}
-
-impl ToCssWithGuard for CssRule {
- // https://drafts.csswg.org/cssom/#serialize-a-css-rule
- fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
- match *self {
- CssRule::Namespace(ref rule) => rule.to_css(guard, dest),
- CssRule::Import(ref lock) => lock.read_with(guard).to_css(guard, dest),
- CssRule::Style(ref lock) => lock.read_with(guard).to_css(guard, dest),
- CssRule::FontFace(ref lock) => lock.read_with(guard).to_css(guard, dest),
- CssRule::FontFeatureValues(ref rule) => rule.to_css(guard, dest),
- CssRule::FontPaletteValues(ref rule) => rule.to_css(guard, dest),
- CssRule::CounterStyle(ref lock) => lock.read_with(guard).to_css(guard, dest),
- CssRule::Keyframes(ref lock) => lock.read_with(guard).to_css(guard, dest),
- CssRule::Media(ref rule) => rule.to_css(guard, dest),
- CssRule::Supports(ref rule) => rule.to_css(guard, dest),
- CssRule::Page(ref lock) => lock.read_with(guard).to_css(guard, dest),
- CssRule::Property(ref rule) => rule.to_css(guard, dest),
- CssRule::Document(ref rule) => rule.to_css(guard, dest),
- CssRule::LayerBlock(ref rule) => rule.to_css(guard, dest),
- CssRule::LayerStatement(ref rule) => rule.to_css(guard, dest),
- CssRule::Container(ref rule) => rule.to_css(guard, dest),
- }
- }
-}
diff --git a/components/style/stylesheets/namespace_rule.rs b/components/style/stylesheets/namespace_rule.rs
deleted file mode 100644
index ad980b70a8b..00000000000
--- a/components/style/stylesheets/namespace_rule.rs
+++ /dev/null
@@ -1,43 +0,0 @@
-/* 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/. */
-
-//! The `@namespace` at-rule.
-
-use crate::shared_lock::{SharedRwLockReadGuard, ToCssWithGuard};
-use crate::str::CssStringWriter;
-use crate::{Namespace, Prefix};
-use cssparser::SourceLocation;
-use std::fmt::{self, Write};
-use style_traits::{CssWriter, ToCss};
-
-/// A `@namespace` rule.
-#[derive(Clone, Debug, PartialEq, ToShmem)]
-#[allow(missing_docs)]
-pub struct NamespaceRule {
- /// The namespace prefix, and `None` if it's the default Namespace
- pub prefix: Option<Prefix>,
- /// The actual namespace url.
- pub url: Namespace,
- /// The source location this rule was found at.
- pub source_location: SourceLocation,
-}
-
-impl ToCssWithGuard for NamespaceRule {
- // https://drafts.csswg.org/cssom/#serialize-a-css-rule CSSNamespaceRule
- fn to_css(
- &self,
- _guard: &SharedRwLockReadGuard,
- dest_str: &mut CssStringWriter,
- ) -> fmt::Result {
- let mut dest = CssWriter::new(dest_str);
- dest.write_str("@namespace ")?;
- if let Some(ref prefix) = self.prefix {
- prefix.to_css(&mut dest)?;
- dest.write_char(' ')?;
- }
- dest.write_str("url(")?;
- self.url.to_string().to_css(&mut dest)?;
- dest.write_str(");")
- }
-}
diff --git a/components/style/stylesheets/origin.rs b/components/style/stylesheets/origin.rs
deleted file mode 100644
index 27ad3fa184a..00000000000
--- a/components/style/stylesheets/origin.rs
+++ /dev/null
@@ -1,247 +0,0 @@
-/* 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/. */
-
-//! [CSS cascade origins](https://drafts.csswg.org/css-cascade/#cascading-origins).
-
-use std::marker::PhantomData;
-use std::ops::BitOrAssign;
-
-/// Each style rule has an origin, which determines where it enters the cascade.
-///
-/// <https://drafts.csswg.org/css-cascade/#cascading-origins>
-#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToShmem, PartialOrd, Ord)]
-#[repr(u8)]
-pub enum Origin {
- /// <https://drafts.csswg.org/css-cascade/#cascade-origin-user-agent>
- UserAgent = 0x1,
-
- /// <https://drafts.csswg.org/css-cascade/#cascade-origin-user>
- User = 0x2,
-
- /// <https://drafts.csswg.org/css-cascade/#cascade-origin-author>
- Author = 0x4,
-}
-
-impl Origin {
- /// Returns an origin that goes in order for `index`.
- ///
- /// This is used for iterating across origins.
- fn from_index(index: i8) -> Option<Self> {
- Some(match index {
- 0 => Origin::Author,
- 1 => Origin::User,
- 2 => Origin::UserAgent,
- _ => return None,
- })
- }
-
- fn to_index(self) -> i8 {
- match self {
- Origin::Author => 0,
- Origin::User => 1,
- Origin::UserAgent => 2,
- }
- }
-
- /// Returns an iterator from this origin, towards all the less specific
- /// origins. So for `UserAgent`, it'd iterate through all origins.
- #[inline]
- pub fn following_including(self) -> OriginSetIterator {
- OriginSetIterator {
- set: OriginSet::ORIGIN_USER | OriginSet::ORIGIN_AUTHOR | OriginSet::ORIGIN_USER_AGENT,
- cur: self.to_index(),
- rev: true,
- }
- }
-}
-
-bitflags! {
- /// A set of origins. This is equivalent to Gecko's OriginFlags.
- #[derive(MallocSizeOf)]
- pub struct OriginSet: u8 {
- /// <https://drafts.csswg.org/css-cascade/#cascade-origin-user-agent>
- const ORIGIN_USER_AGENT = Origin::UserAgent as u8;
- /// <https://drafts.csswg.org/css-cascade/#cascade-origin-user>
- const ORIGIN_USER = Origin::User as u8;
- /// <https://drafts.csswg.org/css-cascade/#cascade-origin-author>
- const ORIGIN_AUTHOR = Origin::Author as u8;
- }
-}
-
-impl OriginSet {
- /// Returns an iterator over the origins present in this `OriginSet`.
- ///
- /// See the `OriginSet` documentation for information about the order
- /// origins are iterated.
- pub fn iter(&self) -> OriginSetIterator {
- OriginSetIterator {
- set: *self,
- cur: 0,
- rev: false,
- }
- }
-}
-
-impl From<Origin> for OriginSet {
- fn from(origin: Origin) -> Self {
- Self::from_bits_truncate(origin as u8)
- }
-}
-
-impl BitOrAssign<Origin> for OriginSet {
- fn bitor_assign(&mut self, origin: Origin) {
- *self |= OriginSet::from(origin);
- }
-}
-
-/// Iterates over the origins present in an `OriginSet`, in order from
-/// highest priority (author) to lower (user agent).
-#[derive(Clone)]
-pub struct OriginSetIterator {
- set: OriginSet,
- cur: i8,
- rev: bool,
-}
-
-impl Iterator for OriginSetIterator {
- type Item = Origin;
-
- fn next(&mut self) -> Option<Origin> {
- loop {
- let origin = Origin::from_index(self.cur)?;
-
- if self.rev {
- self.cur -= 1;
- } else {
- self.cur += 1;
- }
-
- if self.set.contains(origin.into()) {
- return Some(origin);
- }
- }
- }
-}
-
-/// An object that stores a `T` for each origin of the CSS cascade.
-#[derive(Debug, Default, MallocSizeOf)]
-pub struct PerOrigin<T> {
- /// Data for `Origin::UserAgent`.
- pub user_agent: T,
-
- /// Data for `Origin::User`.
- pub user: T,
-
- /// Data for `Origin::Author`.
- pub author: T,
-}
-
-impl<T> PerOrigin<T> {
- /// Returns a reference to the per-origin data for the specified origin.
- #[inline]
- pub fn borrow_for_origin(&self, origin: &Origin) -> &T {
- match *origin {
- Origin::UserAgent => &self.user_agent,
- Origin::User => &self.user,
- Origin::Author => &self.author,
- }
- }
-
- /// Returns a mutable reference to the per-origin data for the specified
- /// origin.
- #[inline]
- pub fn borrow_mut_for_origin(&mut self, origin: &Origin) -> &mut T {
- match *origin {
- Origin::UserAgent => &mut self.user_agent,
- Origin::User => &mut self.user,
- Origin::Author => &mut self.author,
- }
- }
-
- /// Iterates over references to per-origin extra style data, from highest
- /// level (author) to lowest (user agent).
- pub fn iter_origins(&self) -> PerOriginIter<T> {
- PerOriginIter {
- data: &self,
- cur: 0,
- rev: false,
- }
- }
-
- /// Iterates over references to per-origin extra style data, from lowest
- /// level (user agent) to highest (author).
- pub fn iter_origins_rev(&self) -> PerOriginIter<T> {
- PerOriginIter {
- data: &self,
- cur: 2,
- rev: true,
- }
- }
-
- /// Iterates over mutable references to per-origin extra style data, from
- /// highest level (author) to lowest (user agent).
- pub fn iter_mut_origins(&mut self) -> PerOriginIterMut<T> {
- PerOriginIterMut {
- data: self,
- cur: 0,
- _marker: PhantomData,
- }
- }
-}
-
-/// Iterator over `PerOrigin<T>`, from highest level (author) to lowest
-/// (user agent).
-///
-/// We rely on this specific order for correctly looking up @font-face,
-/// @counter-style and @keyframes rules.
-pub struct PerOriginIter<'a, T: 'a> {
- data: &'a PerOrigin<T>,
- cur: i8,
- rev: bool,
-}
-
-impl<'a, T> Iterator for PerOriginIter<'a, T>
-where
- T: 'a,
-{
- type Item = (&'a T, Origin);
-
- fn next(&mut self) -> Option<Self::Item> {
- let origin = Origin::from_index(self.cur)?;
-
- self.cur += if self.rev { -1 } else { 1 };
-
- Some((self.data.borrow_for_origin(&origin), origin))
- }
-}
-
-/// Like `PerOriginIter<T>`, but iterates over mutable references to the
-/// per-origin data.
-///
-/// We must use unsafe code here since it's not possible for the borrow
-/// checker to know that we are safely returning a different reference
-/// each time from `next()`.
-pub struct PerOriginIterMut<'a, T: 'a> {
- data: *mut PerOrigin<T>,
- cur: i8,
- _marker: PhantomData<&'a mut PerOrigin<T>>,
-}
-
-impl<'a, T> Iterator for PerOriginIterMut<'a, T>
-where
- T: 'a,
-{
- type Item = (&'a mut T, Origin);
-
- fn next(&mut self) -> Option<Self::Item> {
- let origin = Origin::from_index(self.cur)?;
-
- self.cur += 1;
-
- Some((
- unsafe { (*self.data).borrow_mut_for_origin(&origin) },
- origin,
- ))
- }
-}
diff --git a/components/style/stylesheets/page_rule.rs b/components/style/stylesheets/page_rule.rs
deleted file mode 100644
index 5cd2458aa25..00000000000
--- a/components/style/stylesheets/page_rule.rs
+++ /dev/null
@@ -1,145 +0,0 @@
-/* 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/. */
-
-//! A [`@page`][page] rule.
-//!
-//! [page]: https://drafts.csswg.org/css2/page.html#page-box
-
-use crate::parser::{Parse, ParserContext};
-use crate::properties::PropertyDeclarationBlock;
-use crate::shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked};
-use crate::shared_lock::{SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard};
-use crate::str::CssStringWriter;
-use crate::values::{AtomIdent, CustomIdent};
-use cssparser::{Parser, SourceLocation};
-#[cfg(feature = "gecko")]
-use malloc_size_of::{MallocSizeOf, MallocSizeOfOps, MallocUnconditionalShallowSizeOf};
-use servo_arc::Arc;
-use std::fmt::{self, Write};
-use style_traits::{CssWriter, ParseError, ToCss};
-
-/// Type of a single [`@page`][page selector]
-///
-/// We do not support pseudo selectors yet.
-/// [page-selectors]: https://drafts.csswg.org/css2/page.html#page-selectors
-#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)]
-pub struct PageSelector(pub AtomIdent);
-
-impl PageSelector {
- /// Checks if the ident matches a page-name's ident.
- ///
- /// This does not currently take pseudo selectors into account.
- #[inline]
- pub fn ident_matches(&self, other: &CustomIdent) -> bool {
- self.0 .0 == other.0
- }
-}
-
-impl Parse for PageSelector {
- fn parse<'i, 't>(
- _context: &ParserContext,
- input: &mut Parser<'i, 't>,
- ) -> Result<Self, ParseError<'i>> {
- let s = input.expect_ident()?;
- Ok(PageSelector(AtomIdent::from(&**s)))
- }
-}
-
-/// A list of [`@page`][page selectors]
-///
-/// [page-selectors]: https://drafts.csswg.org/css2/page.html#page-selectors
-#[derive(Clone, Debug, Default, MallocSizeOf, ToCss, ToShmem)]
-#[css(comma)]
-pub struct PageSelectors(#[css(iterable)] pub Box<[PageSelector]>);
-
-impl PageSelectors {
- /// Creates a new PageSelectors from a Vec, as from parse_comma_separated
- #[inline]
- pub fn new(s: Vec<PageSelector>) -> Self {
- PageSelectors(s.into())
- }
- /// Returns true iff there are any page selectors
- #[inline]
- pub fn is_empty(&self) -> bool {
- self.as_slice().is_empty()
- }
- /// Get the underlying PageSelector data as a slice
- #[inline]
- pub fn as_slice(&self) -> &[PageSelector] {
- &*self.0
- }
-}
-
-impl Parse for PageSelectors {
- fn parse<'i, 't>(
- context: &ParserContext,
- input: &mut Parser<'i, 't>,
- ) -> Result<Self, ParseError<'i>> {
- Ok(PageSelectors::new(input.parse_comma_separated(|i| {
- PageSelector::parse(context, i)
- })?))
- }
-}
-
-/// A [`@page`][page] rule.
-///
-/// This implements only a limited subset of the CSS
-/// 2.2 syntax.
-///
-/// [page]: https://drafts.csswg.org/css2/page.html#page-box
-/// [page-selectors]: https://drafts.csswg.org/css2/page.html#page-selectors
-#[derive(Clone, Debug, ToShmem)]
-pub struct PageRule {
- /// Selectors of the page-rule
- pub selectors: PageSelectors,
- /// The declaration block this page rule contains.
- pub block: Arc<Locked<PropertyDeclarationBlock>>,
- /// The source position this rule was found at.
- pub source_location: SourceLocation,
-}
-
-impl PageRule {
- /// Measure heap usage.
- #[cfg(feature = "gecko")]
- pub fn size_of(&self, guard: &SharedRwLockReadGuard, ops: &mut MallocSizeOfOps) -> usize {
- // Measurement of other fields may be added later.
- self.block.unconditional_shallow_size_of(ops) +
- self.block.read_with(guard).size_of(ops) +
- self.selectors.size_of(ops)
- }
-}
-
-impl ToCssWithGuard for PageRule {
- /// Serialization of PageRule is not specced, adapted from steps for
- /// StyleRule.
- fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
- dest.write_str("@page ")?;
- if !self.selectors.is_empty() {
- self.selectors.to_css(&mut CssWriter::new(dest))?;
- dest.write_char(' ')?;
- }
- dest.write_str("{ ")?;
- let declaration_block = self.block.read_with(guard);
- declaration_block.to_css(dest)?;
- if !declaration_block.declarations().is_empty() {
- dest.write_char(' ')?;
- }
- dest.write_char('}')
- }
-}
-
-impl DeepCloneWithLock for PageRule {
- fn deep_clone_with_lock(
- &self,
- lock: &SharedRwLock,
- guard: &SharedRwLockReadGuard,
- _params: &DeepCloneParams,
- ) -> Self {
- PageRule {
- selectors: self.selectors.clone(),
- block: Arc::new(lock.wrap(self.block.read_with(&guard).clone())),
- source_location: self.source_location.clone(),
- }
- }
-}
diff --git a/components/style/stylesheets/property_rule.rs b/components/style/stylesheets/property_rule.rs
deleted file mode 100644
index 1d1c1c982e9..00000000000
--- a/components/style/stylesheets/property_rule.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-/* 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/. */
-
-pub use crate::properties_and_values::rule::PropertyRuleData as PropertyRule;
diff --git a/components/style/stylesheets/rule_list.rs b/components/style/stylesheets/rule_list.rs
deleted file mode 100644
index ab747565ffe..00000000000
--- a/components/style/stylesheets/rule_list.rs
+++ /dev/null
@@ -1,198 +0,0 @@
-/* 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/. */
-
-//! A list of CSS rules.
-
-use crate::shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked};
-use crate::shared_lock::{SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard};
-use crate::str::CssStringWriter;
-use crate::stylesheets::loader::StylesheetLoader;
-use crate::stylesheets::rule_parser::{InsertRuleContext, State};
-use crate::stylesheets::stylesheet::StylesheetContents;
-use crate::stylesheets::{AllowImportRules, CssRule, RulesMutateError};
-#[cfg(feature = "gecko")]
-use malloc_size_of::{MallocShallowSizeOf, MallocSizeOfOps};
-use servo_arc::Arc;
-use std::fmt::{self, Write};
-
-/// A list of CSS rules.
-#[derive(Debug, ToShmem)]
-pub struct CssRules(pub Vec<CssRule>);
-
-impl CssRules {
- /// Whether this CSS rules is empty.
- pub fn is_empty(&self) -> bool {
- self.0.is_empty()
- }
-}
-
-impl DeepCloneWithLock for CssRules {
- fn deep_clone_with_lock(
- &self,
- lock: &SharedRwLock,
- guard: &SharedRwLockReadGuard,
- params: &DeepCloneParams,
- ) -> Self {
- CssRules(
- self.0
- .iter()
- .map(|x| x.deep_clone_with_lock(lock, guard, params))
- .collect(),
- )
- }
-}
-
-impl CssRules {
- /// Measure heap usage.
- #[cfg(feature = "gecko")]
- pub fn size_of(&self, guard: &SharedRwLockReadGuard, ops: &mut MallocSizeOfOps) -> usize {
- let mut n = self.0.shallow_size_of(ops);
- for rule in self.0.iter() {
- n += rule.size_of(guard, ops);
- }
- n
- }
-
- /// Trivially construct a new set of CSS rules.
- pub fn new(rules: Vec<CssRule>, shared_lock: &SharedRwLock) -> Arc<Locked<CssRules>> {
- Arc::new(shared_lock.wrap(CssRules(rules)))
- }
-
- /// Returns whether all the rules in this list are namespace or import
- /// rules.
- fn only_ns_or_import(&self) -> bool {
- self.0.iter().all(|r| match *r {
- CssRule::Namespace(..) | CssRule::Import(..) => true,
- _ => false,
- })
- }
-
- /// <https://drafts.csswg.org/cssom/#remove-a-css-rule>
- pub fn remove_rule(&mut self, index: usize) -> Result<(), RulesMutateError> {
- // Step 1, 2
- if index >= self.0.len() {
- return Err(RulesMutateError::IndexSize);
- }
-
- {
- // Step 3
- let ref rule = self.0[index];
-
- // Step 4
- if let CssRule::Namespace(..) = *rule {
- if !self.only_ns_or_import() {
- return Err(RulesMutateError::InvalidState);
- }
- }
- }
-
- // Step 5, 6
- self.0.remove(index);
- Ok(())
- }
-
- /// Serializes this CSSRules to CSS text as a block of rules.
- ///
- /// This should be speced into CSSOM spec at some point. See
- /// <https://github.com/w3c/csswg-drafts/issues/1985>
- pub fn to_css_block(
- &self,
- guard: &SharedRwLockReadGuard,
- dest: &mut CssStringWriter,
- ) -> fmt::Result {
- dest.write_str(" {")?;
- self.to_css_block_without_opening(guard, dest)
- }
-
- /// As above, but without the opening curly bracket. That's needed for nesting.
- pub fn to_css_block_without_opening(
- &self,
- guard: &SharedRwLockReadGuard,
- dest: &mut CssStringWriter,
- ) -> fmt::Result {
- for rule in self.0.iter() {
- dest.write_str("\n ")?;
- rule.to_css(guard, dest)?;
- }
- dest.write_str("\n}")
- }
-}
-
-/// A trait to implement helpers for `Arc<Locked<CssRules>>`.
-pub trait CssRulesHelpers {
- /// <https://drafts.csswg.org/cssom/#insert-a-css-rule>
- ///
- /// Written in this funky way because parsing an @import rule may cause us
- /// to clone a stylesheet from the same document due to caching in the CSS
- /// loader.
- ///
- /// TODO(emilio): We could also pass the write guard down into the loader
- /// instead, but that seems overkill.
- fn insert_rule(
- &self,
- lock: &SharedRwLock,
- rule: &str,
- parent_stylesheet_contents: &StylesheetContents,
- index: usize,
- nested: bool,
- loader: Option<&dyn StylesheetLoader>,
- allow_import_rules: AllowImportRules,
- ) -> Result<CssRule, RulesMutateError>;
-}
-
-impl CssRulesHelpers for Locked<CssRules> {
- fn insert_rule(
- &self,
- lock: &SharedRwLock,
- rule: &str,
- parent_stylesheet_contents: &StylesheetContents,
- index: usize,
- nested: bool,
- loader: Option<&dyn StylesheetLoader>,
- allow_import_rules: AllowImportRules,
- ) -> Result<CssRule, RulesMutateError> {
- let new_rule = {
- let read_guard = lock.read();
- let rules = self.read_with(&read_guard);
-
- // Step 1, 2
- if index > rules.0.len() {
- return Err(RulesMutateError::IndexSize);
- }
-
- // Computes the parser state at the given index
- let insert_rule_context = InsertRuleContext {
- rule_list: &rules.0,
- index,
- };
-
- let state = if nested {
- State::Body
- } else if index == 0 {
- State::Start
- } else {
- insert_rule_context.max_rule_state_at_index(index - 1)
- };
-
- // Steps 3, 4, 5, 6
- CssRule::parse(
- &rule,
- insert_rule_context,
- parent_stylesheet_contents,
- lock,
- state,
- loader,
- allow_import_rules,
- )?
- };
-
- {
- let mut write_guard = lock.write();
- let rules = self.write_with(&mut write_guard);
- rules.0.insert(index, new_rule.clone());
- }
-
- Ok(new_rule)
- }
-}
diff --git a/components/style/stylesheets/rule_parser.rs b/components/style/stylesheets/rule_parser.rs
deleted file mode 100644
index 71b27f2c943..00000000000
--- a/components/style/stylesheets/rule_parser.rs
+++ /dev/null
@@ -1,867 +0,0 @@
-/* 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/. */
-
-//! Parsing of the stylesheet contents.
-
-use crate::counter_style::{parse_counter_style_body, parse_counter_style_name_definition};
-use crate::custom_properties::parse_name as parse_custom_property_name;
-use crate::error_reporting::ContextualParseError;
-use crate::font_face::parse_font_face_block;
-use crate::media_queries::MediaList;
-use crate::parser::{Parse, ParserContext};
-use crate::properties::declaration_block::{
- parse_property_declaration_list, DeclarationParserState, PropertyDeclarationBlock,
-};
-use crate::properties_and_values::rule::{parse_property_block, PropertyRuleName};
-use crate::selector_parser::{SelectorImpl, SelectorParser};
-use crate::shared_lock::{Locked, SharedRwLock};
-use crate::str::starts_with_ignore_ascii_case;
-use crate::stylesheets::container_rule::{ContainerCondition, ContainerRule};
-use crate::stylesheets::document_rule::DocumentCondition;
-use crate::stylesheets::font_feature_values_rule::parse_family_name_list;
-use crate::stylesheets::import_rule::{ImportLayer, ImportRule, ImportSupportsCondition};
-use crate::stylesheets::keyframes_rule::parse_keyframe_list;
-use crate::stylesheets::layer_rule::{LayerBlockRule, LayerName, LayerStatementRule};
-use crate::stylesheets::supports_rule::SupportsCondition;
-use crate::stylesheets::{
- AllowImportRules, CorsMode, CssRule, CssRuleType, CssRules, DocumentRule,
- FontFeatureValuesRule, FontPaletteValuesRule, KeyframesRule, MediaRule, NamespaceRule,
- PageRule, PageSelectors, RulesMutateError, StyleRule, StylesheetLoader, SupportsRule,
-};
-use crate::values::computed::font::FamilyName;
-use crate::values::{CssUrl, CustomIdent, DashedIdent, KeyframesName};
-use crate::{Atom, Namespace, Prefix};
-use cssparser::{
- AtRuleParser, BasicParseError, BasicParseErrorKind, CowRcStr, DeclarationParser, Parser,
- ParserState, QualifiedRuleParser, RuleBodyItemParser, RuleBodyParser, SourceLocation,
- SourcePosition,
-};
-use selectors::SelectorList;
-use servo_arc::Arc;
-use style_traits::{ParseError, StyleParseErrorKind};
-
-/// The information we need particularly to do CSSOM insertRule stuff.
-pub struct InsertRuleContext<'a> {
- /// The rule list we're about to insert into.
- pub rule_list: &'a [CssRule],
- /// The index we're about to get inserted at.
- pub index: usize,
-}
-
-impl<'a> InsertRuleContext<'a> {
- /// Returns the max rule state allowable for insertion at a given index in
- /// the rule list.
- pub fn max_rule_state_at_index(&self, index: usize) -> State {
- let rule = match self.rule_list.get(index) {
- Some(rule) => rule,
- None => return State::Body,
- };
- match rule {
- CssRule::Import(..) => State::Imports,
- CssRule::Namespace(..) => State::Namespaces,
- CssRule::LayerStatement(..) => {
- // If there are @import / @namespace after this layer, then
- // we're in the early-layers phase, otherwise we're in the body
- // and everything is fair game.
- let next_non_layer_statement_rule = self.rule_list[index + 1..]
- .iter()
- .find(|r| !matches!(*r, CssRule::LayerStatement(..)));
- if let Some(non_layer) = next_non_layer_statement_rule {
- if matches!(*non_layer, CssRule::Import(..) | CssRule::Namespace(..)) {
- return State::EarlyLayers;
- }
- }
- State::Body
- },
- _ => State::Body,
- }
- }
-}
-
-/// The parser for the top-level rules in a stylesheet.
-pub struct TopLevelRuleParser<'a, 'i> {
- /// A reference to the lock we need to use to create rules.
- pub shared_lock: &'a SharedRwLock,
- /// A reference to a stylesheet loader if applicable, for `@import` rules.
- pub loader: Option<&'a dyn StylesheetLoader>,
- /// The top-level parser context.
- pub context: ParserContext<'a>,
- /// The current state of the parser.
- pub state: State,
- /// Whether we have tried to parse was invalid due to being in the wrong
- /// place (e.g. an @import rule was found while in the `Body` state). Reset
- /// to `false` when `take_had_hierarchy_error` is called.
- pub dom_error: Option<RulesMutateError>,
- /// The info we need insert a rule in a list.
- pub insert_rule_context: Option<InsertRuleContext<'a>>,
- /// Whether @import rules will be allowed.
- pub allow_import_rules: AllowImportRules,
- /// Parser state for declaration blocks in either nested rules or style rules.
- pub declaration_parser_state: DeclarationParserState<'i>,
- /// The rules we've parsed so far.
- pub rules: Vec<CssRule>,
-}
-
-impl<'a, 'i> TopLevelRuleParser<'a, 'i> {
- fn nested<'b>(&'b mut self) -> NestedRuleParser<'b, 'a, 'i> {
- NestedRuleParser {
- shared_lock: self.shared_lock,
- context: &mut self.context,
- declaration_parser_state: &mut self.declaration_parser_state,
- rules: &mut self.rules,
- }
- }
-
- /// Returns the current state of the parser.
- pub fn state(&self) -> State {
- self.state
- }
-
- /// Checks whether we can parse a rule that would transition us to
- /// `new_state`.
- ///
- /// This is usually a simple branch, but we may need more bookkeeping if
- /// doing `insertRule` from CSSOM.
- fn check_state(&mut self, new_state: State) -> bool {
- if self.state > new_state {
- self.dom_error = Some(RulesMutateError::HierarchyRequest);
- return false;
- }
-
- let ctx = match self.insert_rule_context {
- Some(ref ctx) => ctx,
- None => return true,
- };
-
- let max_rule_state = ctx.max_rule_state_at_index(ctx.index);
- if new_state > max_rule_state {
- self.dom_error = Some(RulesMutateError::HierarchyRequest);
- return false;
- }
-
- // If there's anything that isn't a namespace rule (or import rule, but
- // we checked that already at the beginning), reject with a
- // StateError.
- if new_state == State::Namespaces &&
- ctx.rule_list[ctx.index..]
- .iter()
- .any(|r| !matches!(*r, CssRule::Namespace(..)))
- {
- self.dom_error = Some(RulesMutateError::InvalidState);
- return false;
- }
-
- true
- }
-}
-
-/// The current state of the parser.
-#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd)]
-pub enum State {
- /// We haven't started parsing rules.
- Start = 1,
- /// We're parsing early `@layer` statement rules.
- EarlyLayers = 2,
- /// We're parsing `@import` and early `@layer` statement rules.
- Imports = 3,
- /// We're parsing `@namespace` rules.
- Namespaces = 4,
- /// We're parsing the main body of the stylesheet.
- Body = 5,
-}
-
-#[derive(Clone, Debug, MallocSizeOf, ToShmem)]
-/// Vendor prefix.
-pub enum VendorPrefix {
- /// -moz prefix.
- Moz,
- /// -webkit prefix.
- WebKit,
-}
-
-/// A rule prelude for at-rule with block.
-pub enum AtRulePrelude {
- /// A @font-face rule prelude.
- FontFace,
- /// A @font-feature-values rule prelude, with its FamilyName list.
- FontFeatureValues(Vec<FamilyName>),
- /// A @font-palette-values rule prelude, with its identifier.
- FontPaletteValues(DashedIdent),
- /// A @counter-style rule prelude, with its counter style name.
- CounterStyle(CustomIdent),
- /// A @media rule prelude, with its media queries.
- Media(Arc<Locked<MediaList>>),
- /// A @container rule prelude.
- Container(Arc<ContainerCondition>),
- /// An @supports rule, with its conditional
- Supports(SupportsCondition),
- /// A @keyframes rule, with its animation name and vendor prefix if exists.
- Keyframes(KeyframesName, Option<VendorPrefix>),
- /// A @page rule prelude, with its page name if it exists.
- Page(PageSelectors),
- /// A @property rule prelude.
- Property(PropertyRuleName),
- /// A @document rule, with its conditional.
- Document(DocumentCondition),
- /// A @import rule prelude.
- Import(
- CssUrl,
- Arc<Locked<MediaList>>,
- Option<ImportSupportsCondition>,
- ImportLayer,
- ),
- /// A @namespace rule prelude.
- Namespace(Option<Prefix>, Namespace),
- /// A @layer rule prelude.
- Layer(Vec<LayerName>),
-}
-
-impl<'a, 'i> AtRuleParser<'i> for TopLevelRuleParser<'a, 'i> {
- type Prelude = AtRulePrelude;
- type AtRule = SourcePosition;
- type Error = StyleParseErrorKind<'i>;
-
- fn parse_prelude<'t>(
- &mut self,
- name: CowRcStr<'i>,
- input: &mut Parser<'i, 't>,
- ) -> Result<AtRulePrelude, ParseError<'i>> {
- match_ignore_ascii_case! { &*name,
- "import" => {
- if !self.check_state(State::Imports) {
- return Err(input.new_custom_error(StyleParseErrorKind::UnexpectedImportRule))
- }
-
- if let AllowImportRules::No = self.allow_import_rules {
- return Err(input.new_custom_error(StyleParseErrorKind::DisallowedImportRule))
- }
-
- // FIXME(emilio): We should always be able to have a loader
- // around! See bug 1533783.
- if self.loader.is_none() {
- error!("Saw @import rule, but no way to trigger the load");
- return Err(input.new_custom_error(StyleParseErrorKind::UnexpectedImportRule))
- }
-
- let url_string = input.expect_url_or_string()?.as_ref().to_owned();
- let url = CssUrl::parse_from_string(url_string, &self.context, CorsMode::None);
-
- let (layer, supports) = ImportRule::parse_layer_and_supports(input, &mut self.context);
-
- let media = MediaList::parse(&self.context, input);
- let media = Arc::new(self.shared_lock.wrap(media));
-
- return Ok(AtRulePrelude::Import(url, media, supports, layer));
- },
- "namespace" => {
- if !self.check_state(State::Namespaces) {
- return Err(input.new_custom_error(StyleParseErrorKind::UnexpectedNamespaceRule))
- }
-
- let prefix = input.try_parse(|i| i.expect_ident_cloned())
- .map(|s| Prefix::from(s.as_ref())).ok();
- let maybe_namespace = match input.expect_url_or_string() {
- Ok(url_or_string) => url_or_string,
- Err(BasicParseError { kind: BasicParseErrorKind::UnexpectedToken(t), location }) => {
- return Err(location.new_custom_error(StyleParseErrorKind::UnexpectedTokenWithinNamespace(t)))
- }
- Err(e) => return Err(e.into()),
- };
- let url = Namespace::from(maybe_namespace.as_ref());
- return Ok(AtRulePrelude::Namespace(prefix, url));
- },
- // @charset is removed by rust-cssparser if it’s the first rule in the stylesheet
- // anything left is invalid.
- "charset" => {
- self.dom_error = Some(RulesMutateError::HierarchyRequest);
- return Err(input.new_custom_error(StyleParseErrorKind::UnexpectedCharsetRule))
- },
- "layer" => {
- let state_to_check = if self.state <= State::EarlyLayers {
- // The real state depends on whether there's a block or not.
- // We don't know that yet, but the parse_block check deals
- // with that.
- State::EarlyLayers
- } else {
- State::Body
- };
- if !self.check_state(state_to_check) {
- return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
- }
- },
- _ => {
- // All other rules have blocks, so we do this check early in
- // parse_block instead.
- }
- }
-
- AtRuleParser::parse_prelude(&mut self.nested(), name, input)
- }
-
- #[inline]
- fn parse_block<'t>(
- &mut self,
- prelude: AtRulePrelude,
- start: &ParserState,
- input: &mut Parser<'i, 't>,
- ) -> Result<Self::AtRule, ParseError<'i>> {
- if !self.check_state(State::Body) {
- return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
- }
- AtRuleParser::parse_block(&mut self.nested(), prelude, start, input)?;
- self.state = State::Body;
- Ok(start.position())
- }
-
- #[inline]
- fn rule_without_block(
- &mut self,
- prelude: AtRulePrelude,
- start: &ParserState,
- ) -> Result<Self::AtRule, ()> {
- match prelude {
- AtRulePrelude::Import(url, media, supports, layer) => {
- let loader = self
- .loader
- .expect("Expected a stylesheet loader for @import");
-
- let import_rule = loader.request_stylesheet(
- url,
- start.source_location(),
- &self.context,
- &self.shared_lock,
- media,
- supports,
- layer,
- );
-
- self.state = State::Imports;
- self.rules.push(CssRule::Import(import_rule))
- },
- AtRulePrelude::Namespace(prefix, url) => {
- let namespaces = self.context.namespaces.to_mut();
- let prefix = if let Some(prefix) = prefix {
- namespaces.prefixes.insert(prefix.clone(), url.clone());
- Some(prefix)
- } else {
- namespaces.default = Some(url.clone());
- None
- };
-
- self.state = State::Namespaces;
- self.rules.push(CssRule::Namespace(Arc::new(NamespaceRule {
- prefix,
- url,
- source_location: start.source_location(),
- })));
- },
- AtRulePrelude::Layer(..) => {
- AtRuleParser::rule_without_block(&mut self.nested(), prelude, start)?;
- if self.state <= State::EarlyLayers {
- self.state = State::EarlyLayers;
- } else {
- self.state = State::Body;
- }
- },
- _ => AtRuleParser::rule_without_block(&mut self.nested(), prelude, start)?,
- };
-
- Ok(start.position())
- }
-}
-
-impl<'a, 'i> QualifiedRuleParser<'i> for TopLevelRuleParser<'a, 'i> {
- type Prelude = SelectorList<SelectorImpl>;
- type QualifiedRule = SourcePosition;
- type Error = StyleParseErrorKind<'i>;
-
- #[inline]
- fn parse_prelude<'t>(
- &mut self,
- input: &mut Parser<'i, 't>,
- ) -> Result<Self::Prelude, ParseError<'i>> {
- if !self.check_state(State::Body) {
- return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
- }
-
- QualifiedRuleParser::parse_prelude(&mut self.nested(), input)
- }
-
- #[inline]
- fn parse_block<'t>(
- &mut self,
- prelude: Self::Prelude,
- start: &ParserState,
- input: &mut Parser<'i, 't>,
- ) -> Result<Self::QualifiedRule, ParseError<'i>> {
- QualifiedRuleParser::parse_block(&mut self.nested(), prelude, start, input)?;
- self.state = State::Body;
- Ok(start.position())
- }
-}
-
-struct NestedRuleParser<'a, 'b: 'a, 'i> {
- shared_lock: &'a SharedRwLock,
- context: &'a mut ParserContext<'b>,
- declaration_parser_state: &'a mut DeclarationParserState<'i>,
- rules: &'a mut Vec<CssRule>,
-}
-
-struct NestedParseResult {
- rules: Vec<CssRule>,
- declarations: PropertyDeclarationBlock,
-}
-
-impl NestedParseResult {
- fn into_rules(
- mut self,
- shared_lock: &SharedRwLock,
- source_location: SourceLocation,
- ) -> Arc<Locked<CssRules>> {
- lazy_static! {
- static ref AMPERSAND: SelectorList<SelectorImpl> = {
- let list = SelectorList::ampersand();
- list.0
- .iter()
- .for_each(|selector| selector.mark_as_intentionally_leaked());
- list
- };
- };
-
- if !self.declarations.is_empty() {
- self.rules.insert(
- 0,
- CssRule::Style(Arc::new(shared_lock.wrap(StyleRule {
- selectors: AMPERSAND.clone(),
- block: Arc::new(shared_lock.wrap(self.declarations)),
- rules: None,
- source_location,
- }))),
- )
- }
-
- CssRules::new(self.rules, shared_lock)
- }
-}
-
-impl<'a, 'b, 'i> NestedRuleParser<'a, 'b, 'i> {
- /// When nesting is disabled, we prevent parsing at rules and qualified rules inside style
- /// rules.
- fn allow_at_and_qualified_rules(&self) -> bool {
- if !self.context.rule_types.contains(CssRuleType::Style) {
- return true;
- }
- static_prefs::pref!("layout.css.nesting.enabled")
- }
-
- fn nest_for_rule<R>(&mut self, rule_type: CssRuleType, cb: impl FnOnce(&mut Self) -> R) -> R {
- let old_rule_types = self.context.rule_types;
- self.context.rule_types.insert(rule_type);
- let r = cb(self);
- self.context.rule_types = old_rule_types;
- r
- }
-
- fn parse_nested(
- &mut self,
- input: &mut Parser<'i, '_>,
- rule_type: CssRuleType,
- selectors: Option<&SelectorList<SelectorImpl>>,
- ) -> NestedParseResult {
- self.nest_for_rule(rule_type, |parser| {
- let parse_declarations = parser.parse_declarations();
- let mut old_declaration_state = std::mem::take(parser.declaration_parser_state);
- let mut rules = std::mem::take(parser.rules);
- let mut iter = RuleBodyParser::new(input, parser);
- while let Some(result) = iter.next() {
- match result {
- Ok(()) => {},
- Err((error, slice)) => {
- if parse_declarations {
- iter.parser.declaration_parser_state.did_error(
- iter.parser.context,
- error,
- slice,
- );
- } else {
- let location = error.location;
- let error = ContextualParseError::InvalidRule(slice, error);
- iter.parser.context.log_css_error(location, error);
- }
- },
- }
- }
- let declarations = if parse_declarations {
- parser
- .declaration_parser_state
- .report_errors_if_needed(parser.context, selectors);
- parser.declaration_parser_state.take_declarations()
- } else {
- PropertyDeclarationBlock::default()
- };
- debug_assert!(
- !parser.declaration_parser_state.has_parsed_declarations(),
- "Parsed but didn't consume declarations"
- );
- std::mem::swap(parser.declaration_parser_state, &mut old_declaration_state);
- std::mem::swap(parser.rules, &mut rules);
- NestedParseResult {
- rules,
- declarations,
- }
- })
- }
-}
-
-impl<'a, 'b, 'i> AtRuleParser<'i> for NestedRuleParser<'a, 'b, 'i> {
- type Prelude = AtRulePrelude;
- type AtRule = ();
- type Error = StyleParseErrorKind<'i>;
-
- fn parse_prelude<'t>(
- &mut self,
- name: CowRcStr<'i>,
- input: &mut Parser<'i, 't>,
- ) -> Result<Self::Prelude, ParseError<'i>> {
- if !self.allow_at_and_qualified_rules() {
- return Err(input.new_error(BasicParseErrorKind::AtRuleInvalid(name)));
- }
- Ok(match_ignore_ascii_case! { &*name,
- "media" => {
- let media_queries = MediaList::parse(self.context, input);
- let arc = Arc::new(self.shared_lock.wrap(media_queries));
- AtRulePrelude::Media(arc)
- },
- "supports" => {
- let cond = SupportsCondition::parse(input)?;
- AtRulePrelude::Supports(cond)
- },
- "font-face" => {
- AtRulePrelude::FontFace
- },
- "container" if static_prefs::pref!("layout.css.container-queries.enabled") => {
- let condition = Arc::new(ContainerCondition::parse(self.context, input)?);
- AtRulePrelude::Container(condition)
- },
- "layer" => {
- let names = input.try_parse(|input| {
- input.parse_comma_separated(|input| {
- LayerName::parse(self.context, input)
- })
- }).unwrap_or_default();
- AtRulePrelude::Layer(names)
- },
- "font-feature-values" if cfg!(feature = "gecko") => {
- let family_names = parse_family_name_list(self.context, input)?;
- AtRulePrelude::FontFeatureValues(family_names)
- },
- "font-palette-values" if static_prefs::pref!("layout.css.font-palette.enabled") => {
- let name = DashedIdent::parse(self.context, input)?;
- AtRulePrelude::FontPaletteValues(name)
- },
- "counter-style" if cfg!(feature = "gecko") => {
- let name = parse_counter_style_name_definition(input)?;
- AtRulePrelude::CounterStyle(name)
- },
- "keyframes" | "-webkit-keyframes" | "-moz-keyframes" => {
- let prefix = if starts_with_ignore_ascii_case(&*name, "-webkit-") {
- Some(VendorPrefix::WebKit)
- } else if starts_with_ignore_ascii_case(&*name, "-moz-") {
- Some(VendorPrefix::Moz)
- } else {
- None
- };
- if cfg!(feature = "servo") &&
- prefix.as_ref().map_or(false, |p| matches!(*p, VendorPrefix::Moz)) {
- // Servo should not support @-moz-keyframes.
- return Err(input.new_error(BasicParseErrorKind::AtRuleInvalid(name.clone())))
- }
- let name = KeyframesName::parse(self.context, input)?;
- AtRulePrelude::Keyframes(name, prefix)
- },
- "page" if cfg!(feature = "gecko") => {
- AtRulePrelude::Page(
- input.try_parse(|i| PageSelectors::parse(self.context, i)).unwrap_or_default()
- )
- },
- "property" if static_prefs::pref!("layout.css.properties-and-values.enabled") => {
- let name = input.expect_ident_cloned()?;
- let name = parse_custom_property_name(&name).map_err(|_| {
- input.new_custom_error(StyleParseErrorKind::UnexpectedIdent(name.clone()))
- })?;
- AtRulePrelude::Property(PropertyRuleName(Arc::new(Atom::from(name))))
- },
- "-moz-document" if cfg!(feature = "gecko") => {
- let cond = DocumentCondition::parse(self.context, input)?;
- AtRulePrelude::Document(cond)
- },
- _ => return Err(input.new_error(BasicParseErrorKind::AtRuleInvalid(name.clone())))
- })
- }
-
- fn parse_block<'t>(
- &mut self,
- prelude: AtRulePrelude,
- start: &ParserState,
- input: &mut Parser<'i, 't>,
- ) -> Result<(), ParseError<'i>> {
- let rule = match prelude {
- AtRulePrelude::FontFace => self.nest_for_rule(CssRuleType::FontFace, |p| {
- CssRule::FontFace(Arc::new(p.shared_lock.wrap(
- parse_font_face_block(&p.context, input, start.source_location()).into(),
- )))
- }),
- AtRulePrelude::FontFeatureValues(family_names) => {
- self.nest_for_rule(CssRuleType::FontFeatureValues, |p| {
- CssRule::FontFeatureValues(Arc::new(FontFeatureValuesRule::parse(
- &p.context,
- input,
- family_names,
- start.source_location(),
- )))
- })
- },
- AtRulePrelude::FontPaletteValues(name) => {
- self.nest_for_rule(CssRuleType::FontPaletteValues, |p| {
- CssRule::FontPaletteValues(Arc::new(FontPaletteValuesRule::parse(
- &p.context,
- input,
- name,
- start.source_location(),
- )))
- })
- },
- AtRulePrelude::CounterStyle(name) => {
- let body = self.nest_for_rule(CssRuleType::CounterStyle, |p| {
- parse_counter_style_body(name, &p.context, input, start.source_location())
- })?;
- CssRule::CounterStyle(Arc::new(self.shared_lock.wrap(body)))
- },
- AtRulePrelude::Media(media_queries) => {
- let source_location = start.source_location();
- CssRule::Media(Arc::new(MediaRule {
- media_queries,
- rules: self
- .parse_nested(input, CssRuleType::Media, None)
- .into_rules(self.shared_lock, source_location),
- source_location,
- }))
- },
- AtRulePrelude::Supports(condition) => {
- let enabled =
- self.nest_for_rule(CssRuleType::Style, |p| condition.eval(&p.context));
- let source_location = start.source_location();
- CssRule::Supports(Arc::new(SupportsRule {
- condition,
- rules: self
- .parse_nested(input, CssRuleType::Supports, None)
- .into_rules(self.shared_lock, source_location),
- enabled,
- source_location,
- }))
- },
- AtRulePrelude::Keyframes(name, vendor_prefix) => {
- self.nest_for_rule(CssRuleType::Keyframe, |p| {
- CssRule::Keyframes(Arc::new(p.shared_lock.wrap(KeyframesRule {
- name,
- keyframes: parse_keyframe_list(&mut p.context, input, p.shared_lock),
- vendor_prefix,
- source_location: start.source_location(),
- })))
- })
- },
- AtRulePrelude::Page(selectors) => {
- let declarations = self.nest_for_rule(CssRuleType::Page, |p| {
- // TODO: Support nesting in @page rules?
- parse_property_declaration_list(&p.context, input, None)
- });
- CssRule::Page(Arc::new(self.shared_lock.wrap(PageRule {
- selectors,
- block: Arc::new(self.shared_lock.wrap(declarations)),
- source_location: start.source_location(),
- })))
- },
- AtRulePrelude::Property(name) => self.nest_for_rule(CssRuleType::Property, |p| {
- CssRule::Property(Arc::new(parse_property_block(
- &p.context,
- input,
- name,
- start.source_location(),
- )))
- }),
- AtRulePrelude::Document(condition) => {
- if !cfg!(feature = "gecko") {
- unreachable!()
- }
- let source_location = start.source_location();
- CssRule::Document(Arc::new(DocumentRule {
- condition,
- rules: self
- .parse_nested(input, CssRuleType::Document, None)
- .into_rules(self.shared_lock, source_location),
- source_location,
- }))
- },
- AtRulePrelude::Container(condition) => {
- let source_location = start.source_location();
- CssRule::Container(Arc::new(ContainerRule {
- condition,
- rules: self
- .parse_nested(input, CssRuleType::Container, None)
- .into_rules(self.shared_lock, source_location),
- source_location,
- }))
- },
- AtRulePrelude::Layer(names) => {
- let name = match names.len() {
- 0 | 1 => names.into_iter().next(),
- _ => return Err(input.new_error(BasicParseErrorKind::AtRuleBodyInvalid)),
- };
- let source_location = start.source_location();
- CssRule::LayerBlock(Arc::new(LayerBlockRule {
- name,
- rules: self
- .parse_nested(input, CssRuleType::LayerBlock, None)
- .into_rules(self.shared_lock, source_location),
- source_location,
- }))
- },
- AtRulePrelude::Import(..) | AtRulePrelude::Namespace(..) => {
- // These rules don't have blocks.
- return Err(input.new_unexpected_token_error(cssparser::Token::CurlyBracketBlock));
- },
- };
- self.rules.push(rule);
- Ok(())
- }
-
- #[inline]
- fn rule_without_block(
- &mut self,
- prelude: AtRulePrelude,
- start: &ParserState,
- ) -> Result<(), ()> {
- let rule = match prelude {
- AtRulePrelude::Layer(names) => {
- if names.is_empty() {
- return Err(());
- }
- CssRule::LayerStatement(Arc::new(LayerStatementRule {
- names,
- source_location: start.source_location(),
- }))
- },
- _ => return Err(()),
- };
- self.rules.push(rule);
- Ok(())
- }
-}
-
-#[inline(never)]
-fn check_for_useless_selector(
- input: &mut Parser,
- context: &ParserContext,
- selectors: &SelectorList<SelectorImpl>,
-) {
- use cssparser::ToCss;
-
- 'selector_loop: for selector in selectors.0.iter() {
- let mut current = selector.iter();
- loop {
- let mut found_host = false;
- let mut found_non_host = false;
- for component in &mut current {
- if component.is_host() {
- found_host = true;
- } else {
- found_non_host = true;
- }
- if found_host && found_non_host {
- let location = input.current_source_location();
- context.log_css_error(
- location,
- ContextualParseError::NeverMatchingHostSelector(selector.to_css_string()),
- );
- continue 'selector_loop;
- }
- }
- if current.next_sequence().is_none() {
- break;
- }
- }
- }
-}
-
-impl<'a, 'b, 'i> QualifiedRuleParser<'i> for NestedRuleParser<'a, 'b, 'i> {
- type Prelude = SelectorList<SelectorImpl>;
- type QualifiedRule = ();
- type Error = StyleParseErrorKind<'i>;
-
- fn parse_prelude<'t>(
- &mut self,
- input: &mut Parser<'i, 't>,
- ) -> Result<Self::Prelude, ParseError<'i>> {
- let selector_parser = SelectorParser {
- stylesheet_origin: self.context.stylesheet_origin,
- namespaces: &self.context.namespaces,
- url_data: self.context.url_data,
- for_supports_rule: false,
- };
- let selectors = SelectorList::parse(&selector_parser, input)?;
- if self.context.error_reporting_enabled() {
- check_for_useless_selector(input, &self.context, &selectors);
- }
- Ok(selectors)
- }
-
- fn parse_block<'t>(
- &mut self,
- selectors: Self::Prelude,
- start: &ParserState,
- input: &mut Parser<'i, 't>,
- ) -> Result<(), ParseError<'i>> {
- let result = self.parse_nested(input, CssRuleType::Style, Some(&selectors));
- let block = Arc::new(self.shared_lock.wrap(result.declarations));
- self.rules
- .push(CssRule::Style(Arc::new(self.shared_lock.wrap(StyleRule {
- selectors,
- block,
- rules: if result.rules.is_empty() {
- None
- } else {
- Some(CssRules::new(result.rules, self.shared_lock))
- },
- source_location: start.source_location(),
- }))));
- Ok(())
- }
-}
-
-impl<'a, 'b, 'i> DeclarationParser<'i> for NestedRuleParser<'a, 'b, 'i> {
- type Declaration = ();
- type Error = StyleParseErrorKind<'i>;
- fn parse_value<'t>(
- &mut self,
- name: CowRcStr<'i>,
- input: &mut Parser<'i, 't>,
- ) -> Result<(), ParseError<'i>> {
- self.declaration_parser_state
- .parse_value(self.context, name, input)
- }
-}
-
-impl<'a, 'b, 'i> RuleBodyItemParser<'i, (), StyleParseErrorKind<'i>>
- for NestedRuleParser<'a, 'b, 'i>
-{
- fn parse_qualified(&self) -> bool {
- self.allow_at_and_qualified_rules()
- }
-
- /// If nesting is disabled, we can't get there for a non-style-rule. If it's enabled, we parse
- /// raw declarations there.
- fn parse_declarations(&self) -> bool {
- self.context.rule_types.contains(CssRuleType::Style)
- }
-}
diff --git a/components/style/stylesheets/rules_iterator.rs b/components/style/stylesheets/rules_iterator.rs
deleted file mode 100644
index 0ab2b42c0bc..00000000000
--- a/components/style/stylesheets/rules_iterator.rs
+++ /dev/null
@@ -1,326 +0,0 @@
-/* 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/. */
-
-//! An iterator over a list of rules.
-
-use crate::context::QuirksMode;
-use crate::media_queries::Device;
-use crate::shared_lock::SharedRwLockReadGuard;
-use crate::stylesheets::{CssRule, DocumentRule, ImportRule, MediaRule, SupportsRule};
-use smallvec::SmallVec;
-use std::slice;
-
-/// An iterator over a list of rules.
-pub struct RulesIterator<'a, 'b, C>
-where
- 'b: 'a,
- C: NestedRuleIterationCondition + 'static,
-{
- device: &'a Device,
- quirks_mode: QuirksMode,
- guard: &'a SharedRwLockReadGuard<'b>,
- stack: SmallVec<[slice::Iter<'a, CssRule>; 3]>,
- _phantom: ::std::marker::PhantomData<C>,
-}
-
-impl<'a, 'b, C> RulesIterator<'a, 'b, C>
-where
- 'b: 'a,
- C: NestedRuleIterationCondition + 'static,
-{
- /// Creates a new `RulesIterator` to iterate over `rules`.
- pub fn new(
- device: &'a Device,
- quirks_mode: QuirksMode,
- guard: &'a SharedRwLockReadGuard<'b>,
- rules: slice::Iter<'a, CssRule>,
- ) -> Self {
- let mut stack = SmallVec::new();
- stack.push(rules);
- Self {
- device,
- quirks_mode,
- guard,
- stack,
- _phantom: ::std::marker::PhantomData,
- }
- }
-
- /// Skips all the remaining children of the last nested rule processed.
- pub fn skip_children(&mut self) {
- self.stack.pop();
- }
-
- /// Returns the children of `rule`, and whether `rule` is effective.
- pub fn children(
- rule: &'a CssRule,
- device: &'a Device,
- quirks_mode: QuirksMode,
- guard: &'a SharedRwLockReadGuard<'_>,
- effective: &mut bool,
- ) -> Option<slice::Iter<'a, CssRule>> {
- *effective = true;
- match *rule {
- CssRule::Namespace(_) |
- CssRule::FontFace(_) |
- CssRule::CounterStyle(_) |
- CssRule::Keyframes(_) |
- CssRule::Page(_) |
- CssRule::Property(_) |
- CssRule::LayerStatement(_) |
- CssRule::FontFeatureValues(_) |
- CssRule::FontPaletteValues(_) => None,
- CssRule::Style(ref style_rule) => {
- let style_rule = style_rule.read_with(guard);
- style_rule
- .rules
- .as_ref()
- .map(|r| r.read_with(guard).0.iter())
- },
- CssRule::Import(ref import_rule) => {
- let import_rule = import_rule.read_with(guard);
- if !C::process_import(guard, device, quirks_mode, import_rule) {
- *effective = false;
- return None;
- }
- Some(import_rule.stylesheet.rules(guard).iter())
- },
- CssRule::Document(ref doc_rule) => {
- if !C::process_document(guard, device, quirks_mode, doc_rule) {
- *effective = false;
- return None;
- }
- Some(doc_rule.rules.read_with(guard).0.iter())
- },
- CssRule::Container(ref container_rule) => {
- Some(container_rule.rules.read_with(guard).0.iter())
- },
- CssRule::Media(ref media_rule) => {
- if !C::process_media(guard, device, quirks_mode, media_rule) {
- *effective = false;
- return None;
- }
- Some(media_rule.rules.read_with(guard).0.iter())
- },
- CssRule::Supports(ref supports_rule) => {
- if !C::process_supports(guard, device, quirks_mode, supports_rule) {
- *effective = false;
- return None;
- }
- Some(supports_rule.rules.read_with(guard).0.iter())
- },
- CssRule::LayerBlock(ref layer_rule) => Some(layer_rule.rules.read_with(guard).0.iter()),
- }
- }
-}
-
-impl<'a, 'b, C> Iterator for RulesIterator<'a, 'b, C>
-where
- 'b: 'a,
- C: NestedRuleIterationCondition + 'static,
-{
- type Item = &'a CssRule;
-
- fn next(&mut self) -> Option<Self::Item> {
- while !self.stack.is_empty() {
- let rule = {
- let nested_iter = self.stack.last_mut().unwrap();
- match nested_iter.next() {
- Some(r) => r,
- None => {
- self.stack.pop();
- continue;
- },
- }
- };
-
- let mut effective = true;
- let children = Self::children(
- rule,
- self.device,
- self.quirks_mode,
- self.guard,
- &mut effective,
- );
- if !effective {
- continue;
- }
-
- if let Some(children) = children {
- // NOTE: It's important that `children` gets pushed even if
- // empty, so that `skip_children()` works as expected.
- self.stack.push(children);
- }
-
- return Some(rule);
- }
-
- None
- }
-}
-
-/// RulesIterator.
-pub trait NestedRuleIterationCondition {
- /// Whether we should process the nested rules in a given `@import` rule.
- fn process_import(
- guard: &SharedRwLockReadGuard,
- device: &Device,
- quirks_mode: QuirksMode,
- rule: &ImportRule,
- ) -> bool;
-
- /// Whether we should process the nested rules in a given `@media` rule.
- fn process_media(
- guard: &SharedRwLockReadGuard,
- device: &Device,
- quirks_mode: QuirksMode,
- rule: &MediaRule,
- ) -> bool;
-
- /// Whether we should process the nested rules in a given `@-moz-document`
- /// rule.
- fn process_document(
- guard: &SharedRwLockReadGuard,
- device: &Device,
- quirks_mode: QuirksMode,
- rule: &DocumentRule,
- ) -> bool;
-
- /// Whether we should process the nested rules in a given `@supports` rule.
- fn process_supports(
- guard: &SharedRwLockReadGuard,
- device: &Device,
- quirks_mode: QuirksMode,
- rule: &SupportsRule,
- ) -> bool;
-}
-
-/// A struct that represents the condition that a rule applies to the document.
-pub struct EffectiveRules;
-
-impl EffectiveRules {
- /// Returns whether a given rule is effective.
- pub fn is_effective(
- guard: &SharedRwLockReadGuard,
- device: &Device,
- quirks_mode: QuirksMode,
- rule: &CssRule,
- ) -> bool {
- match *rule {
- CssRule::Import(ref import_rule) => {
- let import_rule = import_rule.read_with(guard);
- Self::process_import(guard, device, quirks_mode, import_rule)
- },
- CssRule::Document(ref doc_rule) => {
- Self::process_document(guard, device, quirks_mode, doc_rule)
- },
- CssRule::Media(ref media_rule) => {
- Self::process_media(guard, device, quirks_mode, media_rule)
- },
- CssRule::Supports(ref supports_rule) => {
- Self::process_supports(guard, device, quirks_mode, supports_rule)
- },
- _ => true,
- }
- }
-}
-
-impl NestedRuleIterationCondition for EffectiveRules {
- fn process_import(
- guard: &SharedRwLockReadGuard,
- device: &Device,
- quirks_mode: QuirksMode,
- rule: &ImportRule,
- ) -> bool {
- match rule.stylesheet.media(guard) {
- Some(m) => m.evaluate(device, quirks_mode),
- None => true,
- }
- }
-
- fn process_media(
- guard: &SharedRwLockReadGuard,
- device: &Device,
- quirks_mode: QuirksMode,
- rule: &MediaRule,
- ) -> bool {
- rule.media_queries
- .read_with(guard)
- .evaluate(device, quirks_mode)
- }
-
- fn process_document(
- _: &SharedRwLockReadGuard,
- device: &Device,
- _: QuirksMode,
- rule: &DocumentRule,
- ) -> bool {
- rule.condition.evaluate(device)
- }
-
- fn process_supports(
- _: &SharedRwLockReadGuard,
- _: &Device,
- _: QuirksMode,
- rule: &SupportsRule,
- ) -> bool {
- rule.enabled
- }
-}
-
-/// A filter that processes all the rules in a rule list.
-pub struct AllRules;
-
-impl NestedRuleIterationCondition for AllRules {
- fn process_import(
- _: &SharedRwLockReadGuard,
- _: &Device,
- _: QuirksMode,
- _: &ImportRule,
- ) -> bool {
- true
- }
-
- fn process_media(_: &SharedRwLockReadGuard, _: &Device, _: QuirksMode, _: &MediaRule) -> bool {
- true
- }
-
- fn process_document(
- _: &SharedRwLockReadGuard,
- _: &Device,
- _: QuirksMode,
- _: &DocumentRule,
- ) -> bool {
- true
- }
-
- fn process_supports(
- _: &SharedRwLockReadGuard,
- _: &Device,
- _: QuirksMode,
- _: &SupportsRule,
- ) -> bool {
- true
- }
-}
-
-/// An iterator over all the effective rules of a stylesheet.
-///
-/// NOTE: This iterator recurses into `@import` rules.
-pub type EffectiveRulesIterator<'a, 'b> = RulesIterator<'a, 'b, EffectiveRules>;
-
-impl<'a, 'b> EffectiveRulesIterator<'a, 'b> {
- /// Returns an iterator over the effective children of a rule, even if
- /// `rule` itself is not effective.
- pub fn effective_children(
- device: &'a Device,
- quirks_mode: QuirksMode,
- guard: &'a SharedRwLockReadGuard<'b>,
- rule: &'a CssRule,
- ) -> Self {
- let children =
- RulesIterator::<AllRules>::children(rule, device, quirks_mode, guard, &mut false);
- EffectiveRulesIterator::new(device, quirks_mode, guard, children.unwrap_or([].iter()))
- }
-}
diff --git a/components/style/stylesheets/style_rule.rs b/components/style/stylesheets/style_rule.rs
deleted file mode 100644
index d5a22d6fc20..00000000000
--- a/components/style/stylesheets/style_rule.rs
+++ /dev/null
@@ -1,104 +0,0 @@
-/* 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/. */
-
-//! A style rule.
-
-use crate::properties::PropertyDeclarationBlock;
-use crate::selector_parser::SelectorImpl;
-use crate::shared_lock::{
- DeepCloneParams, DeepCloneWithLock, Locked, SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard,
-};
-use crate::str::CssStringWriter;
-use crate::stylesheets::CssRules;
-use cssparser::SourceLocation;
-#[cfg(feature = "gecko")]
-use malloc_size_of::MallocUnconditionalShallowSizeOf;
-#[cfg(feature = "gecko")]
-use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
-use selectors::SelectorList;
-use servo_arc::Arc;
-use std::fmt::{self, Write};
-
-/// A style rule, with selectors and declarations.
-#[derive(Debug, ToShmem)]
-pub struct StyleRule {
- /// The list of selectors in this rule.
- pub selectors: SelectorList<SelectorImpl>,
- /// The declaration block with the properties it contains.
- pub block: Arc<Locked<PropertyDeclarationBlock>>,
- /// The nested rules to this style rule. Only non-`None` when nesting is enabled.
- pub rules: Option<Arc<Locked<CssRules>>>,
- /// The location in the sheet where it was found.
- pub source_location: SourceLocation,
-}
-
-impl DeepCloneWithLock for StyleRule {
- /// Deep clones this StyleRule.
- fn deep_clone_with_lock(
- &self,
- lock: &SharedRwLock,
- guard: &SharedRwLockReadGuard,
- params: &DeepCloneParams,
- ) -> StyleRule {
- StyleRule {
- selectors: self.selectors.clone(),
- block: Arc::new(lock.wrap(self.block.read_with(guard).clone())),
- rules: self.rules.as_ref().map(|rules| {
- let rules = rules.read_with(guard);
- Arc::new(lock.wrap(rules.deep_clone_with_lock(lock, guard, params)))
- }),
- source_location: self.source_location.clone(),
- }
- }
-}
-
-impl StyleRule {
- /// Measure heap usage.
- #[cfg(feature = "gecko")]
- pub fn size_of(&self, guard: &SharedRwLockReadGuard, ops: &mut MallocSizeOfOps) -> usize {
- let mut n = 0;
- n += self.selectors.0.size_of(ops);
- n += self.block.unconditional_shallow_size_of(ops) +
- self.block.read_with(guard).size_of(ops);
- if let Some(ref rules) = self.rules {
- n += rules.unconditional_shallow_size_of(ops) +
- rules.read_with(guard).size_of(guard, ops)
- }
- n
- }
-}
-
-impl ToCssWithGuard for StyleRule {
- /// https://drafts.csswg.org/cssom/#serialize-a-css-rule CSSStyleRule
- fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
- use cssparser::ToCss;
- // Step 1
- self.selectors.to_css(dest)?;
- dest.write_str(" {")?;
-
- // Step 2
- let declaration_block = self.block.read_with(guard);
- let has_declarations = !declaration_block.declarations().is_empty();
-
- // Step 3
- if let Some(ref rules) = self.rules {
- let rules = rules.read_with(guard);
- // Step 6 (here because it's more convenient)
- if !rules.is_empty() {
- if has_declarations {
- dest.write_str("\n ")?;
- declaration_block.to_css(dest)?;
- }
- return rules.to_css_block_without_opening(guard, dest);
- }
- }
-
- // Steps 4 & 5
- if has_declarations {
- dest.write_char(' ')?;
- declaration_block.to_css(dest)?;
- }
- dest.write_str(" }")
- }
-}
diff --git a/components/style/stylesheets/stylesheet.rs b/components/style/stylesheets/stylesheet.rs
deleted file mode 100644
index 6c205e03c66..00000000000
--- a/components/style/stylesheets/stylesheet.rs
+++ /dev/null
@@ -1,605 +0,0 @@
-/* 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/. */
-
-use crate::context::QuirksMode;
-use crate::error_reporting::{ContextualParseError, ParseErrorReporter};
-use crate::media_queries::{Device, MediaList};
-use crate::parser::ParserContext;
-use crate::shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked};
-use crate::shared_lock::{SharedRwLock, SharedRwLockReadGuard};
-use crate::stylesheets::loader::StylesheetLoader;
-use crate::stylesheets::rule_parser::{State, TopLevelRuleParser};
-use crate::stylesheets::rules_iterator::{EffectiveRules, EffectiveRulesIterator};
-use crate::stylesheets::rules_iterator::{NestedRuleIterationCondition, RulesIterator};
-use crate::stylesheets::{CssRule, CssRules, Origin, UrlExtraData};
-use crate::use_counters::UseCounters;
-use crate::{Namespace, Prefix};
-use cssparser::{Parser, ParserInput, StyleSheetParser};
-use fxhash::FxHashMap;
-#[cfg(feature = "gecko")]
-use malloc_size_of::{MallocSizeOfOps, MallocUnconditionalShallowSizeOf};
-use parking_lot::RwLock;
-use servo_arc::Arc;
-use std::sync::atomic::{AtomicBool, Ordering};
-use style_traits::ParsingMode;
-
-/// This structure holds the user-agent and user stylesheets.
-pub struct UserAgentStylesheets {
- /// The lock used for user-agent stylesheets.
- pub shared_lock: SharedRwLock,
- /// The user or user agent stylesheets.
- pub user_or_user_agent_stylesheets: Vec<DocumentStyleSheet>,
- /// The quirks mode stylesheet.
- pub quirks_mode_stylesheet: DocumentStyleSheet,
-}
-
-/// A set of namespaces applying to a given stylesheet.
-///
-/// The namespace id is used in gecko
-#[derive(Clone, Debug, Default, MallocSizeOf)]
-#[allow(missing_docs)]
-pub struct Namespaces {
- pub default: Option<Namespace>,
- pub prefixes: FxHashMap<Prefix, Namespace>,
-}
-
-/// The contents of a given stylesheet. This effectively maps to a
-/// StyleSheetInner in Gecko.
-#[derive(Debug)]
-pub struct StylesheetContents {
- /// List of rules in the order they were found (important for
- /// cascading order)
- pub rules: Arc<Locked<CssRules>>,
- /// The origin of this stylesheet.
- pub origin: Origin,
- /// The url data this stylesheet should use.
- pub url_data: RwLock<UrlExtraData>,
- /// The namespaces that apply to this stylesheet.
- pub namespaces: RwLock<Namespaces>,
- /// The quirks mode of this stylesheet.
- pub quirks_mode: QuirksMode,
- /// This stylesheet's source map URL.
- pub source_map_url: RwLock<Option<String>>,
- /// This stylesheet's source URL.
- pub source_url: RwLock<Option<String>>,
-
- /// We don't want to allow construction outside of this file, to guarantee
- /// that all contents are created with Arc<>.
- _forbid_construction: (),
-}
-
-impl StylesheetContents {
- /// Parse a given CSS string, with a given url-data, origin, and
- /// quirks mode.
- pub fn from_str(
- css: &str,
- url_data: UrlExtraData,
- origin: Origin,
- shared_lock: &SharedRwLock,
- stylesheet_loader: Option<&dyn StylesheetLoader>,
- error_reporter: Option<&dyn ParseErrorReporter>,
- quirks_mode: QuirksMode,
- line_number_offset: u32,
- use_counters: Option<&UseCounters>,
- allow_import_rules: AllowImportRules,
- sanitization_data: Option<&mut SanitizationData>,
- ) -> Arc<Self> {
- let (namespaces, rules, source_map_url, source_url) = Stylesheet::parse_rules(
- css,
- &url_data,
- origin,
- &shared_lock,
- stylesheet_loader,
- error_reporter,
- quirks_mode,
- line_number_offset,
- use_counters,
- allow_import_rules,
- sanitization_data,
- );
-
- Arc::new(Self {
- rules: CssRules::new(rules, &shared_lock),
- origin,
- url_data: RwLock::new(url_data),
- namespaces: RwLock::new(namespaces),
- quirks_mode,
- source_map_url: RwLock::new(source_map_url),
- source_url: RwLock::new(source_url),
- _forbid_construction: (),
- })
- }
-
- /// Creates a new StylesheetContents with the specified pre-parsed rules,
- /// origin, URL data, and quirks mode.
- ///
- /// Since the rules have already been parsed, and the intention is that
- /// this function is used for read only User Agent style sheets, an empty
- /// namespace map is used, and the source map and source URLs are set to
- /// None.
- ///
- /// An empty namespace map should be fine, as it is only used for parsing,
- /// not serialization of existing selectors. Since UA sheets are read only,
- /// we should never need the namespace map.
- pub fn from_data(
- rules: Arc<Locked<CssRules>>,
- origin: Origin,
- url_data: UrlExtraData,
- quirks_mode: QuirksMode,
- ) -> Arc<Self> {
- Arc::new(Self {
- rules,
- origin,
- url_data: RwLock::new(url_data),
- namespaces: RwLock::new(Namespaces::default()),
- quirks_mode,
- source_map_url: RwLock::new(None),
- source_url: RwLock::new(None),
- _forbid_construction: (),
- })
- }
-
- /// Same as above, but ensuring that the rules are static.
- pub fn from_shared_data(
- rules: Arc<Locked<CssRules>>,
- origin: Origin,
- url_data: UrlExtraData,
- quirks_mode: QuirksMode,
- ) -> Arc<Self> {
- debug_assert!(rules.is_static());
- Self::from_data(rules, origin, url_data, quirks_mode)
- }
-
- /// Returns a reference to the list of rules.
- #[inline]
- pub fn rules<'a, 'b: 'a>(&'a self, guard: &'b SharedRwLockReadGuard) -> &'a [CssRule] {
- &self.rules.read_with(guard).0
- }
-
- /// Measure heap usage.
- #[cfg(feature = "gecko")]
- pub fn size_of(&self, guard: &SharedRwLockReadGuard, ops: &mut MallocSizeOfOps) -> usize {
- if self.rules.is_static() {
- return 0;
- }
- // Measurement of other fields may be added later.
- self.rules.unconditional_shallow_size_of(ops) +
- self.rules.read_with(guard).size_of(guard, ops)
- }
-}
-
-impl DeepCloneWithLock for StylesheetContents {
- fn deep_clone_with_lock(
- &self,
- lock: &SharedRwLock,
- guard: &SharedRwLockReadGuard,
- params: &DeepCloneParams,
- ) -> Self {
- // Make a deep clone of the rules, using the new lock.
- let rules = self
- .rules
- .read_with(guard)
- .deep_clone_with_lock(lock, guard, params);
-
- Self {
- rules: Arc::new(lock.wrap(rules)),
- quirks_mode: self.quirks_mode,
- origin: self.origin,
- url_data: RwLock::new((*self.url_data.read()).clone()),
- namespaces: RwLock::new((*self.namespaces.read()).clone()),
- source_map_url: RwLock::new((*self.source_map_url.read()).clone()),
- source_url: RwLock::new((*self.source_url.read()).clone()),
- _forbid_construction: (),
- }
- }
-}
-
-/// The structure servo uses to represent a stylesheet.
-#[derive(Debug)]
-pub struct Stylesheet {
- /// The contents of this stylesheet.
- pub contents: Arc<StylesheetContents>,
- /// The lock used for objects inside this stylesheet
- pub shared_lock: SharedRwLock,
- /// List of media associated with the Stylesheet.
- pub media: Arc<Locked<MediaList>>,
- /// Whether this stylesheet should be disabled.
- pub disabled: AtomicBool,
-}
-
-macro_rules! rule_filter {
- ($( $method: ident($variant:ident => $rule_type: ident), )+) => {
- $(
- #[allow(missing_docs)]
- fn $method<F>(&self, device: &Device, guard: &SharedRwLockReadGuard, mut f: F)
- where F: FnMut(&crate::stylesheets::$rule_type),
- {
- use crate::stylesheets::CssRule;
-
- for rule in self.effective_rules(device, guard) {
- if let CssRule::$variant(ref lock) = *rule {
- let rule = lock.read_with(guard);
- f(&rule)
- }
- }
- }
- )+
- }
-}
-
-/// A trait to represent a given stylesheet in a document.
-pub trait StylesheetInDocument: ::std::fmt::Debug {
- /// Get whether this stylesheet is enabled.
- fn enabled(&self) -> bool;
-
- /// Get the media associated with this stylesheet.
- fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList>;
-
- /// Returns a reference to the list of rules in this stylesheet.
- fn rules<'a, 'b: 'a>(&'a self, guard: &'b SharedRwLockReadGuard) -> &'a [CssRule] {
- self.contents().rules(guard)
- }
-
- /// Returns a reference to the contents of the stylesheet.
- fn contents(&self) -> &StylesheetContents;
-
- /// Return an iterator using the condition `C`.
- #[inline]
- fn iter_rules<'a, 'b, C>(
- &'a self,
- device: &'a Device,
- guard: &'a SharedRwLockReadGuard<'b>,
- ) -> RulesIterator<'a, 'b, C>
- where
- C: NestedRuleIterationCondition,
- {
- let contents = self.contents();
- RulesIterator::new(
- device,
- contents.quirks_mode,
- guard,
- contents.rules(guard).iter(),
- )
- }
-
- /// Returns whether the style-sheet applies for the current device.
- fn is_effective_for_device(&self, device: &Device, guard: &SharedRwLockReadGuard) -> bool {
- match self.media(guard) {
- Some(medialist) => medialist.evaluate(device, self.contents().quirks_mode),
- None => true,
- }
- }
-
- /// Return an iterator over the effective rules within the style-sheet, as
- /// according to the supplied `Device`.
- #[inline]
- fn effective_rules<'a, 'b>(
- &'a self,
- device: &'a Device,
- guard: &'a SharedRwLockReadGuard<'b>,
- ) -> EffectiveRulesIterator<'a, 'b> {
- self.iter_rules::<EffectiveRules>(device, guard)
- }
-
- rule_filter! {
- effective_font_face_rules(FontFace => FontFaceRule),
- }
-}
-
-impl StylesheetInDocument for Stylesheet {
- fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList> {
- Some(self.media.read_with(guard))
- }
-
- fn enabled(&self) -> bool {
- !self.disabled()
- }
-
- #[inline]
- fn contents(&self) -> &StylesheetContents {
- &self.contents
- }
-}
-
-/// A simple wrapper over an `Arc<Stylesheet>`, with pointer comparison, and
-/// suitable for its use in a `StylesheetSet`.
-#[derive(Clone, Debug)]
-#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
-pub struct DocumentStyleSheet(
- #[cfg_attr(feature = "servo", ignore_malloc_size_of = "Arc")] pub Arc<Stylesheet>,
-);
-
-impl PartialEq for DocumentStyleSheet {
- fn eq(&self, other: &Self) -> bool {
- Arc::ptr_eq(&self.0, &other.0)
- }
-}
-
-impl StylesheetInDocument for DocumentStyleSheet {
- fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList> {
- self.0.media(guard)
- }
-
- fn enabled(&self) -> bool {
- self.0.enabled()
- }
-
- #[inline]
- fn contents(&self) -> &StylesheetContents {
- self.0.contents()
- }
-}
-
-/// The kind of sanitization to use when parsing a stylesheet.
-#[repr(u8)]
-#[derive(Clone, Copy, Debug, PartialEq)]
-pub enum SanitizationKind {
- /// Perform no sanitization.
- None,
- /// Allow only @font-face, style rules, and @namespace.
- Standard,
- /// Allow everything but conditional rules.
- NoConditionalRules,
-}
-
-/// Whether @import rules are allowed.
-#[repr(u8)]
-#[derive(Clone, Copy, Debug, PartialEq)]
-pub enum AllowImportRules {
- /// @import rules will be parsed.
- Yes,
- /// @import rules will not be parsed.
- No,
-}
-
-impl SanitizationKind {
- fn allows(self, rule: &CssRule) -> bool {
- debug_assert_ne!(self, SanitizationKind::None);
- // NOTE(emilio): If this becomes more complex (not filtering just by
- // top-level rules), we should thread all the data through nested rules
- // and such. But this doesn't seem necessary at the moment.
- let is_standard = matches!(self, SanitizationKind::Standard);
- match *rule {
- CssRule::Document(..) |
- CssRule::Media(..) |
- CssRule::Supports(..) |
- CssRule::Import(..) |
- CssRule::Container(..) |
- // TODO(emilio): Perhaps Layer should not be always sanitized? But
- // we sanitize @media and co, so this seems safer for now.
- CssRule::LayerStatement(..) |
- CssRule::LayerBlock(..) => false,
-
- CssRule::FontFace(..) | CssRule::Namespace(..) | CssRule::Style(..) => true,
-
- CssRule::Keyframes(..) |
- CssRule::Page(..) |
- CssRule::Property(..) |
- CssRule::FontFeatureValues(..) |
- CssRule::FontPaletteValues(..) |
- CssRule::CounterStyle(..) => !is_standard,
- }
- }
-}
-
-/// A struct to hold the data relevant to style sheet sanitization.
-#[derive(Debug)]
-pub struct SanitizationData {
- kind: SanitizationKind,
- output: String,
-}
-
-impl SanitizationData {
- /// Create a new input for sanitization.
- #[inline]
- pub fn new(kind: SanitizationKind) -> Option<Self> {
- if matches!(kind, SanitizationKind::None) {
- return None;
- }
- Some(Self {
- kind,
- output: String::new(),
- })
- }
-
- /// Take the sanitized output.
- #[inline]
- pub fn take(self) -> String {
- self.output
- }
-}
-
-impl Stylesheet {
- /// Updates an empty stylesheet from a given string of text.
- pub fn update_from_str(
- existing: &Stylesheet,
- css: &str,
- url_data: UrlExtraData,
- stylesheet_loader: Option<&dyn StylesheetLoader>,
- error_reporter: Option<&dyn ParseErrorReporter>,
- line_number_offset: u32,
- allow_import_rules: AllowImportRules,
- ) {
- // FIXME: Consider adding use counters to Servo?
- let (namespaces, rules, source_map_url, source_url) = Self::parse_rules(
- css,
- &url_data,
- existing.contents.origin,
- &existing.shared_lock,
- stylesheet_loader,
- error_reporter,
- existing.contents.quirks_mode,
- line_number_offset,
- /* use_counters = */ None,
- allow_import_rules,
- /* sanitization_data = */ None,
- );
-
- *existing.contents.url_data.write() = url_data;
- *existing.contents.namespaces.write() = namespaces;
-
- // Acquire the lock *after* parsing, to minimize the exclusive section.
- let mut guard = existing.shared_lock.write();
- *existing.contents.rules.write_with(&mut guard) = CssRules(rules);
- *existing.contents.source_map_url.write() = source_map_url;
- *existing.contents.source_url.write() = source_url;
- }
-
- fn parse_rules(
- css: &str,
- url_data: &UrlExtraData,
- origin: Origin,
- shared_lock: &SharedRwLock,
- stylesheet_loader: Option<&dyn StylesheetLoader>,
- error_reporter: Option<&dyn ParseErrorReporter>,
- quirks_mode: QuirksMode,
- line_number_offset: u32,
- use_counters: Option<&UseCounters>,
- allow_import_rules: AllowImportRules,
- mut sanitization_data: Option<&mut SanitizationData>,
- ) -> (Namespaces, Vec<CssRule>, Option<String>, Option<String>) {
- let mut input = ParserInput::new_with_line_number_offset(css, line_number_offset);
- let mut input = Parser::new(&mut input);
-
- let context = ParserContext::new(
- origin,
- url_data,
- None,
- ParsingMode::DEFAULT,
- quirks_mode,
- /* namespaces = */ Default::default(),
- error_reporter,
- use_counters,
- );
-
- let mut rule_parser = TopLevelRuleParser {
- shared_lock,
- loader: stylesheet_loader,
- context,
- state: State::Start,
- dom_error: None,
- insert_rule_context: None,
- allow_import_rules,
- declaration_parser_state: Default::default(),
- rules: Vec::new(),
- };
-
- {
- let mut iter = StyleSheetParser::new(&mut input, &mut rule_parser);
- while let Some(result) = iter.next() {
- match result {
- Ok(rule_start) => {
- // TODO(emilio, nesting): sanitize nested CSS rules, probably?
- if let Some(ref mut data) = sanitization_data {
- if let Some(ref rule) = iter.parser.rules.last() {
- if !data.kind.allows(rule) {
- iter.parser.rules.pop();
- continue;
- }
- }
- let end = iter.input.position().byte_index();
- data.output.push_str(&css[rule_start.byte_index()..end]);
- }
- },
- Err((error, slice)) => {
- let location = error.location;
- let error = ContextualParseError::InvalidRule(slice, error);
- iter.parser.context.log_css_error(location, error);
- },
- }
- }
- }
-
- let source_map_url = input.current_source_map_url().map(String::from);
- let source_url = input.current_source_url().map(String::from);
- (
- rule_parser.context.namespaces.into_owned(),
- rule_parser.rules,
- source_map_url,
- source_url,
- )
- }
-
- /// Creates an empty stylesheet and parses it with a given base url, origin
- /// and media.
- ///
- /// Effectively creates a new stylesheet and forwards the hard work to
- /// `Stylesheet::update_from_str`.
- pub fn from_str(
- css: &str,
- url_data: UrlExtraData,
- origin: Origin,
- media: Arc<Locked<MediaList>>,
- shared_lock: SharedRwLock,
- stylesheet_loader: Option<&dyn StylesheetLoader>,
- error_reporter: Option<&dyn ParseErrorReporter>,
- quirks_mode: QuirksMode,
- line_number_offset: u32,
- allow_import_rules: AllowImportRules,
- ) -> Self {
- // FIXME: Consider adding use counters to Servo?
- let contents = StylesheetContents::from_str(
- css,
- url_data,
- origin,
- &shared_lock,
- stylesheet_loader,
- error_reporter,
- quirks_mode,
- line_number_offset,
- /* use_counters = */ None,
- allow_import_rules,
- /* sanitized_output = */ None,
- );
-
- Stylesheet {
- contents,
- shared_lock,
- media,
- disabled: AtomicBool::new(false),
- }
- }
-
- /// Returns whether the stylesheet has been explicitly disabled through the
- /// CSSOM.
- pub fn disabled(&self) -> bool {
- self.disabled.load(Ordering::SeqCst)
- }
-
- /// Records that the stylesheet has been explicitly disabled through the
- /// CSSOM.
- ///
- /// Returns whether the the call resulted in a change in disabled state.
- ///
- /// Disabled stylesheets remain in the document, but their rules are not
- /// added to the Stylist.
- pub fn set_disabled(&self, disabled: bool) -> bool {
- self.disabled.swap(disabled, Ordering::SeqCst) != disabled
- }
-}
-
-#[cfg(feature = "servo")]
-impl Clone for Stylesheet {
- fn clone(&self) -> Self {
- // Create a new lock for our clone.
- let lock = self.shared_lock.clone();
- let guard = self.shared_lock.read();
-
- // Make a deep clone of the media, using the new lock.
- let media = self.media.read_with(&guard).clone();
- let media = Arc::new(lock.wrap(media));
- let contents = Arc::new(self.contents.deep_clone_with_lock(
- &lock,
- &guard,
- &DeepCloneParams,
- ));
-
- Stylesheet {
- contents,
- media,
- shared_lock: lock,
- disabled: AtomicBool::new(self.disabled.load(Ordering::SeqCst)),
- }
- }
-}
diff --git a/components/style/stylesheets/supports_rule.rs b/components/style/stylesheets/supports_rule.rs
deleted file mode 100644
index 936bcdb385f..00000000000
--- a/components/style/stylesheets/supports_rule.rs
+++ /dev/null
@@ -1,448 +0,0 @@
-/* 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/. */
-
-//! [@supports rules](https://drafts.csswg.org/css-conditional-3/#at-supports)
-
-use crate::font_face::{FontFaceSourceFormatKeyword, FontFaceSourceTechFlags};
-use crate::parser::ParserContext;
-use crate::properties::{PropertyDeclaration, PropertyId, SourcePropertyDeclaration};
-use crate::selector_parser::{SelectorImpl, SelectorParser};
-use crate::shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked};
-use crate::shared_lock::{SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard};
-use crate::str::CssStringWriter;
-use crate::stylesheets::{CssRuleType, CssRules};
-use cssparser::parse_important;
-use cssparser::{Delimiter, Parser, SourceLocation, Token};
-use cssparser::{ParseError as CssParseError, ParserInput};
-#[cfg(feature = "gecko")]
-use malloc_size_of::{MallocSizeOfOps, MallocUnconditionalShallowSizeOf};
-use selectors::parser::{Selector, SelectorParseErrorKind};
-use servo_arc::Arc;
-use std::ffi::{CStr, CString};
-use std::fmt::{self, Write};
-use std::str;
-use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
-
-/// An [`@supports`][supports] rule.
-///
-/// [supports]: https://drafts.csswg.org/css-conditional-3/#at-supports
-#[derive(Debug, ToShmem)]
-pub struct SupportsRule {
- /// The parsed condition
- pub condition: SupportsCondition,
- /// Child rules
- pub rules: Arc<Locked<CssRules>>,
- /// The result of evaluating the condition
- pub enabled: bool,
- /// The line and column of the rule's source code.
- pub source_location: SourceLocation,
-}
-
-impl SupportsRule {
- /// Measure heap usage.
- #[cfg(feature = "gecko")]
- pub fn size_of(&self, guard: &SharedRwLockReadGuard, ops: &mut MallocSizeOfOps) -> usize {
- // Measurement of other fields may be added later.
- self.rules.unconditional_shallow_size_of(ops) +
- self.rules.read_with(guard).size_of(guard, ops)
- }
-}
-
-impl ToCssWithGuard for SupportsRule {
- fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
- dest.write_str("@supports ")?;
- self.condition.to_css(&mut CssWriter::new(dest))?;
- self.rules.read_with(guard).to_css_block(guard, dest)
- }
-}
-
-impl DeepCloneWithLock for SupportsRule {
- fn deep_clone_with_lock(
- &self,
- lock: &SharedRwLock,
- guard: &SharedRwLockReadGuard,
- params: &DeepCloneParams,
- ) -> Self {
- let rules = self.rules.read_with(guard);
- SupportsRule {
- condition: self.condition.clone(),
- rules: Arc::new(lock.wrap(rules.deep_clone_with_lock(lock, guard, params))),
- enabled: self.enabled,
- source_location: self.source_location.clone(),
- }
- }
-}
-
-/// An @supports condition
-///
-/// <https://drafts.csswg.org/css-conditional-3/#at-supports>
-#[derive(Clone, Debug, ToShmem)]
-pub enum SupportsCondition {
- /// `not (condition)`
- Not(Box<SupportsCondition>),
- /// `(condition)`
- Parenthesized(Box<SupportsCondition>),
- /// `(condition) and (condition) and (condition) ..`
- And(Vec<SupportsCondition>),
- /// `(condition) or (condition) or (condition) ..`
- Or(Vec<SupportsCondition>),
- /// `property-ident: value` (value can be any tokens)
- Declaration(Declaration),
- /// A `selector()` function.
- Selector(RawSelector),
- /// `-moz-bool-pref("pref-name")`
- /// Since we need to pass it through FFI to get the pref value,
- /// we store it as CString directly.
- MozBoolPref(CString),
- /// `font-format(<font-format>)`
- FontFormat(FontFaceSourceFormatKeyword),
- /// `font-tech(<font-tech>)`
- FontTech(FontFaceSourceTechFlags),
- /// `(any tokens)` or `func(any tokens)`
- FutureSyntax(String),
-}
-
-impl SupportsCondition {
- /// Parse a condition
- ///
- /// <https://drafts.csswg.org/css-conditional/#supports_condition>
- pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
- if input.try_parse(|i| i.expect_ident_matching("not")).is_ok() {
- let inner = SupportsCondition::parse_in_parens(input)?;
- return Ok(SupportsCondition::Not(Box::new(inner)));
- }
-
- let in_parens = SupportsCondition::parse_in_parens(input)?;
-
- let location = input.current_source_location();
- let (keyword, wrapper) = match input.next() {
- // End of input
- Err(..) => return Ok(in_parens),
- Ok(&Token::Ident(ref ident)) => {
- match_ignore_ascii_case! { &ident,
- "and" => ("and", SupportsCondition::And as fn(_) -> _),
- "or" => ("or", SupportsCondition::Or as fn(_) -> _),
- _ => return Err(location.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(ident.clone())))
- }
- },
- Ok(t) => return Err(location.new_unexpected_token_error(t.clone())),
- };
-
- let mut conditions = Vec::with_capacity(2);
- conditions.push(in_parens);
- loop {
- conditions.push(SupportsCondition::parse_in_parens(input)?);
- if input
- .try_parse(|input| input.expect_ident_matching(keyword))
- .is_err()
- {
- // Did not find the expected keyword.
- // If we found some other token, it will be rejected by
- // `Parser::parse_entirely` somewhere up the stack.
- return Ok(wrapper(conditions));
- }
- }
- }
-
- /// Parses a functional supports condition.
- fn parse_functional<'i, 't>(
- function: &str,
- input: &mut Parser<'i, 't>,
- ) -> Result<Self, ParseError<'i>> {
- match_ignore_ascii_case! { function,
- // Although this is an internal syntax, it is not necessary
- // to check parsing context as far as we accept any
- // unexpected token as future syntax, and evaluate it to
- // false when not in chrome / ua sheet.
- // See https://drafts.csswg.org/css-conditional-3/#general_enclosed
- "-moz-bool-pref" => {
- let name = {
- let name = input.expect_string()?;
- CString::new(name.as_bytes())
- }.map_err(|_| input.new_custom_error(StyleParseErrorKind::UnspecifiedError))?;
- Ok(SupportsCondition::MozBoolPref(name))
- },
- "selector" => {
- let pos = input.position();
- consume_any_value(input)?;
- Ok(SupportsCondition::Selector(RawSelector(
- input.slice_from(pos).to_owned()
- )))
- },
- "font-format" if static_prefs::pref!("layout.css.font-tech.enabled") => {
- let kw = FontFaceSourceFormatKeyword::parse(input)?;
- Ok(SupportsCondition::FontFormat(kw))
- },
- "font-tech" if static_prefs::pref!("layout.css.font-tech.enabled") => {
- let flag = FontFaceSourceTechFlags::parse_one(input)?;
- Ok(SupportsCondition::FontTech(flag))
- },
- _ => {
- Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
- },
- }
- }
-
- /// Parses an `@import` condition as per
- /// https://drafts.csswg.org/css-cascade-5/#typedef-import-conditions
- pub fn parse_for_import<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
- input.expect_function_matching("supports")?;
- input.parse_nested_block(parse_condition_or_declaration)
- }
-
- /// <https://drafts.csswg.org/css-conditional-3/#supports_condition_in_parens>
- fn parse_in_parens<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
- // Whitespace is normally taken care of in `Parser::next`, but we want to not include it in
- // `pos` for the SupportsCondition::FutureSyntax cases.
- input.skip_whitespace();
- let pos = input.position();
- let location = input.current_source_location();
- match *input.next()? {
- Token::ParenthesisBlock => {
- let nested = input
- .try_parse(|input| input.parse_nested_block(parse_condition_or_declaration));
- if let Ok(nested) = nested {
- return Ok(Self::Parenthesized(Box::new(nested)));
- }
- },
- Token::Function(ref ident) => {
- let ident = ident.clone();
- let nested = input.try_parse(|input| {
- input.parse_nested_block(|input| {
- SupportsCondition::parse_functional(&ident, input)
- })
- });
- if nested.is_ok() {
- return nested;
- }
- },
- ref t => return Err(location.new_unexpected_token_error(t.clone())),
- }
- input.parse_nested_block(consume_any_value)?;
- Ok(SupportsCondition::FutureSyntax(
- input.slice_from(pos).to_owned(),
- ))
- }
-
- /// Evaluate a supports condition
- pub fn eval(&self, cx: &ParserContext) -> bool {
- match *self {
- SupportsCondition::Not(ref cond) => !cond.eval(cx),
- SupportsCondition::Parenthesized(ref cond) => cond.eval(cx),
- SupportsCondition::And(ref vec) => vec.iter().all(|c| c.eval(cx)),
- SupportsCondition::Or(ref vec) => vec.iter().any(|c| c.eval(cx)),
- SupportsCondition::Declaration(ref decl) => decl.eval(cx),
- SupportsCondition::MozBoolPref(ref name) => eval_moz_bool_pref(name, cx),
- SupportsCondition::Selector(ref selector) => selector.eval(cx),
- SupportsCondition::FontFormat(ref format) => eval_font_format(format),
- SupportsCondition::FontTech(ref tech) => eval_font_tech(tech),
- SupportsCondition::FutureSyntax(_) => false,
- }
- }
-}
-
-#[cfg(feature = "gecko")]
-fn eval_moz_bool_pref(name: &CStr, cx: &ParserContext) -> bool {
- use crate::gecko_bindings::bindings;
- if !cx.in_ua_or_chrome_sheet() {
- return false;
- }
- unsafe { bindings::Gecko_GetBoolPrefValue(name.as_ptr()) }
-}
-
-#[cfg(feature = "gecko")]
-fn eval_font_format(kw: &FontFaceSourceFormatKeyword) -> bool {
- use crate::gecko_bindings::bindings;
- unsafe { bindings::Gecko_IsFontFormatSupported(*kw) }
-}
-
-#[cfg(feature = "gecko")]
-fn eval_font_tech(flag: &FontFaceSourceTechFlags) -> bool {
- use crate::gecko_bindings::bindings;
- unsafe { bindings::Gecko_IsFontTechSupported(*flag) }
-}
-
-#[cfg(feature = "servo")]
-fn eval_moz_bool_pref(_: &CStr, _: &ParserContext) -> bool {
- false
-}
-
-#[cfg(feature = "servo")]
-fn eval_font_format(_: &FontFaceSourceFormatKeyword) -> bool {
- false
-}
-
-#[cfg(feature = "servo")]
-fn eval_font_tech(_: &FontFaceSourceTechFlags) -> bool {
- false
-}
-
-/// supports_condition | declaration
-/// <https://drafts.csswg.org/css-conditional/#dom-css-supports-conditiontext-conditiontext>
-pub fn parse_condition_or_declaration<'i, 't>(
- input: &mut Parser<'i, 't>,
-) -> Result<SupportsCondition, ParseError<'i>> {
- if let Ok(condition) = input.try_parse(SupportsCondition::parse) {
- Ok(condition)
- } else {
- Declaration::parse(input).map(SupportsCondition::Declaration)
- }
-}
-
-impl ToCss for SupportsCondition {
- fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
- where
- W: Write,
- {
- match *self {
- SupportsCondition::Not(ref cond) => {
- dest.write_str("not ")?;
- cond.to_css(dest)
- },
- SupportsCondition::Parenthesized(ref cond) => {
- dest.write_char('(')?;
- cond.to_css(dest)?;
- dest.write_char(')')
- },
- SupportsCondition::And(ref vec) => {
- let mut first = true;
- for cond in vec {
- if !first {
- dest.write_str(" and ")?;
- }
- first = false;
- cond.to_css(dest)?;
- }
- Ok(())
- },
- SupportsCondition::Or(ref vec) => {
- let mut first = true;
- for cond in vec {
- if !first {
- dest.write_str(" or ")?;
- }
- first = false;
- cond.to_css(dest)?;
- }
- Ok(())
- },
- SupportsCondition::Declaration(ref decl) => decl.to_css(dest),
- SupportsCondition::Selector(ref selector) => {
- dest.write_str("selector(")?;
- selector.to_css(dest)?;
- dest.write_char(')')
- },
- SupportsCondition::MozBoolPref(ref name) => {
- dest.write_str("-moz-bool-pref(")?;
- let name =
- str::from_utf8(name.as_bytes()).expect("Should be parsed from valid UTF-8");
- name.to_css(dest)?;
- dest.write_char(')')
- },
- SupportsCondition::FontFormat(ref kw) => {
- dest.write_str("font-format(")?;
- kw.to_css(dest)?;
- dest.write_char(')')
- },
- SupportsCondition::FontTech(ref flag) => {
- dest.write_str("font-tech(")?;
- flag.to_css(dest)?;
- dest.write_char(')')
- },
- SupportsCondition::FutureSyntax(ref s) => dest.write_str(&s),
- }
- }
-}
-
-#[derive(Clone, Debug, ToShmem)]
-/// A possibly-invalid CSS selector.
-pub struct RawSelector(pub String);
-
-impl ToCss for RawSelector {
- fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
- where
- W: Write,
- {
- dest.write_str(&self.0)
- }
-}
-
-impl RawSelector {
- /// Tries to evaluate a `selector()` function.
- pub fn eval(&self, context: &ParserContext) -> bool {
- let mut input = ParserInput::new(&self.0);
- let mut input = Parser::new(&mut input);
- input
- .parse_entirely(|input| -> Result<(), CssParseError<()>> {
- let parser = SelectorParser {
- namespaces: &context.namespaces,
- stylesheet_origin: context.stylesheet_origin,
- url_data: context.url_data,
- for_supports_rule: true,
- };
-
- Selector::<SelectorImpl>::parse(&parser, input)
- .map_err(|_| input.new_custom_error(()))?;
-
- Ok(())
- })
- .is_ok()
- }
-}
-
-#[derive(Clone, Debug, ToShmem)]
-/// A possibly-invalid property declaration
-pub struct Declaration(pub String);
-
-impl ToCss for Declaration {
- fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
- where
- W: Write,
- {
- dest.write_str(&self.0)
- }
-}
-
-/// <https://drafts.csswg.org/css-syntax-3/#typedef-any-value>
-fn consume_any_value<'i, 't>(input: &mut Parser<'i, 't>) -> Result<(), ParseError<'i>> {
- input.expect_no_error_token().map_err(|err| err.into())
-}
-
-impl Declaration {
- /// Parse a declaration
- pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Declaration, ParseError<'i>> {
- let pos = input.position();
- input.expect_ident()?;
- input.expect_colon()?;
- consume_any_value(input)?;
- Ok(Declaration(input.slice_from(pos).to_owned()))
- }
-
- /// Determine if a declaration parses
- ///
- /// <https://drafts.csswg.org/css-conditional-3/#support-definition>
- pub fn eval(&self, context: &ParserContext) -> bool {
- debug_assert!(context.rule_types().contains(CssRuleType::Style));
-
- let mut input = ParserInput::new(&self.0);
- let mut input = Parser::new(&mut input);
- input
- .parse_entirely(|input| -> Result<(), CssParseError<()>> {
- let prop = input.expect_ident_cloned().unwrap();
- input.expect_colon().unwrap();
-
- let id =
- PropertyId::parse(&prop, context).map_err(|_| input.new_custom_error(()))?;
-
- let mut declarations = SourcePropertyDeclaration::default();
- input.parse_until_before(Delimiter::Bang, |input| {
- PropertyDeclaration::parse_into(&mut declarations, id, &context, input)
- .map_err(|_| input.new_custom_error(()))
- })?;
- let _ = input.try_parse(parse_important);
- Ok(())
- })
- .is_ok()
- }
-}