tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

mod.rs (32115B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
      4 
      5 //! Style sheets and their CSS rules.
      6 
      7 pub mod container_rule;
      8 mod counter_style_rule;
      9 mod document_rule;
     10 mod font_face_rule;
     11 pub mod font_feature_values_rule;
     12 pub mod font_palette_values_rule;
     13 pub mod import_rule;
     14 pub mod keyframes_rule;
     15 pub mod layer_rule;
     16 mod loader;
     17 mod margin_rule;
     18 mod media_rule;
     19 mod namespace_rule;
     20 mod nested_declarations_rule;
     21 pub mod origin;
     22 mod page_rule;
     23 pub mod position_try_rule;
     24 mod property_rule;
     25 mod rule_list;
     26 mod rule_parser;
     27 mod rules_iterator;
     28 pub mod scope_rule;
     29 mod starting_style_rule;
     30 mod style_rule;
     31 mod stylesheet;
     32 pub mod supports_rule;
     33 
     34 use crate::derives::*;
     35 #[cfg(feature = "gecko")]
     36 use crate::gecko_bindings::sugar::refptr::RefCounted;
     37 #[cfg(feature = "gecko")]
     38 use crate::gecko_bindings::{bindings, structs};
     39 use crate::parser::{NestingContext, ParserContext};
     40 use crate::properties::{parse_property_declaration_list, PropertyDeclarationBlock};
     41 use crate::shared_lock::{DeepCloneWithLock, Locked};
     42 use crate::shared_lock::{SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard};
     43 use cssparser::{parse_one_rule, Parser, ParserInput};
     44 #[cfg(feature = "gecko")]
     45 use malloc_size_of::{MallocSizeOfOps, MallocUnconditionalShallowSizeOf};
     46 use servo_arc::Arc;
     47 use std::borrow::Cow;
     48 use std::fmt::{self, Write};
     49 #[cfg(feature = "gecko")]
     50 use std::mem::{self, ManuallyDrop};
     51 use style_traits::{CssStringWriter, ParsingMode};
     52 use to_shmem::{SharedMemoryBuilder, ToShmem};
     53 
     54 pub use self::container_rule::ContainerRule;
     55 pub use self::counter_style_rule::CounterStyleRule;
     56 pub use self::document_rule::DocumentRule;
     57 pub use self::font_face_rule::FontFaceRule;
     58 pub use self::font_feature_values_rule::FontFeatureValuesRule;
     59 pub use self::font_palette_values_rule::FontPaletteValuesRule;
     60 pub use self::import_rule::ImportRule;
     61 pub use self::keyframes_rule::KeyframesRule;
     62 pub use self::layer_rule::{LayerBlockRule, LayerStatementRule};
     63 pub use self::loader::StylesheetLoader;
     64 pub use self::margin_rule::{MarginRule, MarginRuleType};
     65 pub use self::media_rule::{
     66    CustomMediaCondition, CustomMediaEvaluator, CustomMediaMap, CustomMediaRule, MediaRule,
     67 };
     68 pub use self::namespace_rule::NamespaceRule;
     69 pub use self::nested_declarations_rule::NestedDeclarationsRule;
     70 pub use self::origin::{Origin, OriginSet, OriginSetIterator, PerOrigin, PerOriginIter};
     71 pub use self::page_rule::{PagePseudoClassFlags, PageRule, PageSelector, PageSelectors};
     72 pub use self::position_try_rule::PositionTryRule;
     73 pub use self::property_rule::PropertyRule;
     74 pub use self::rule_list::CssRules;
     75 pub use self::rule_parser::{InsertRuleContext, State, TopLevelRuleParser};
     76 pub use self::rules_iterator::{AllRules, EffectiveRules};
     77 pub use self::rules_iterator::{
     78    EffectiveRulesIterator, NestedRuleIterationCondition, RulesIterator,
     79 };
     80 pub use self::scope_rule::ScopeRule;
     81 pub use self::starting_style_rule::StartingStyleRule;
     82 pub use self::style_rule::StyleRule;
     83 pub use self::stylesheet::{AllowImportRules, SanitizationData, SanitizationKind};
     84 pub use self::stylesheet::{DocumentStyleSheet, Namespaces, Stylesheet};
     85 pub use self::stylesheet::{StylesheetContents, StylesheetInDocument, UserAgentStylesheets};
     86 pub use self::supports_rule::SupportsRule;
     87 
     88 /// The CORS mode used for a CSS load.
     89 #[repr(u8)]
     90 #[derive(Clone, Copy, Debug, Eq, PartialEq, ToShmem)]
     91 pub enum CorsMode {
     92    /// No CORS mode, so cross-origin loads can be done.
     93    None,
     94    /// Anonymous CORS request.
     95    Anonymous,
     96 }
     97 
     98 /// Extra data that the backend may need to resolve url values.
     99 ///
    100 /// If the usize's lowest bit is 0, then this is a strong reference to a
    101 /// structs::URLExtraData object.
    102 ///
    103 /// Otherwise, shifting the usize's bits the right by one gives the
    104 /// UserAgentStyleSheetID value corresponding to the style sheet whose
    105 /// URLExtraData this is, which is stored in URLExtraData_sShared.  We don't
    106 /// hold a strong reference to that object from here, but we rely on that
    107 /// array's objects being held alive until shutdown.
    108 ///
    109 /// We use this packed representation rather than an enum so that
    110 /// `from_ptr_ref` can work.
    111 #[cfg(feature = "gecko")]
    112 // Although deriving MallocSizeOf means it always returns 0, that is fine because UrlExtraData
    113 // objects are reference-counted.
    114 #[derive(MallocSizeOf, PartialEq)]
    115 #[repr(C)]
    116 pub struct UrlExtraData(usize);
    117 
    118 /// Extra data that the backend may need to resolve url values.
    119 #[cfg(feature = "servo")]
    120 #[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)]
    121 pub struct UrlExtraData(#[ignore_malloc_size_of = "Arc"] pub Arc<::url::Url>);
    122 
    123 #[cfg(feature = "servo")]
    124 impl UrlExtraData {
    125    /// True if this URL scheme is chrome.
    126    pub fn chrome_rules_enabled(&self) -> bool {
    127        self.0.scheme() == "chrome"
    128    }
    129 
    130    /// Get the interior Url as a string.
    131    pub fn as_str(&self) -> &str {
    132        self.0.as_str()
    133    }
    134 }
    135 
    136 #[cfg(feature = "servo")]
    137 impl From<::url::Url> for UrlExtraData {
    138    fn from(url: ::url::Url) -> Self {
    139        Self(Arc::new(url))
    140    }
    141 }
    142 
    143 #[cfg(not(feature = "gecko"))]
    144 impl ToShmem for UrlExtraData {
    145    fn to_shmem(&self, _builder: &mut SharedMemoryBuilder) -> to_shmem::Result<Self> {
    146        unimplemented!("If servo wants to share stylesheets across processes, ToShmem for Url must be implemented");
    147    }
    148 }
    149 
    150 #[cfg(feature = "gecko")]
    151 impl Clone for UrlExtraData {
    152    fn clone(&self) -> UrlExtraData {
    153        UrlExtraData::new(self.ptr())
    154    }
    155 }
    156 
    157 #[cfg(feature = "gecko")]
    158 impl Drop for UrlExtraData {
    159    fn drop(&mut self) {
    160        // No need to release when we have an index into URLExtraData_sShared.
    161        if self.0 & 1 == 0 {
    162            unsafe {
    163                self.as_ref().release();
    164            }
    165        }
    166    }
    167 }
    168 
    169 #[cfg(feature = "gecko")]
    170 impl ToShmem for UrlExtraData {
    171    fn to_shmem(&self, _builder: &mut SharedMemoryBuilder) -> to_shmem::Result<Self> {
    172        if self.0 & 1 == 0 {
    173            let shared_extra_datas = unsafe {
    174                std::ptr::addr_of!(structs::URLExtraData_sShared)
    175                    .as_ref()
    176                    .unwrap()
    177            };
    178            let self_ptr = self.as_ref() as *const _ as *mut _;
    179            let sheet_id = shared_extra_datas
    180                .iter()
    181                .position(|r| r.mRawPtr == self_ptr);
    182            let sheet_id = match sheet_id {
    183                Some(id) => id,
    184                None => {
    185                    return Err(String::from(
    186                        "ToShmem failed for UrlExtraData: expected sheet's URLExtraData to be in \
    187                         URLExtraData::sShared",
    188                    ));
    189                },
    190            };
    191            Ok(ManuallyDrop::new(UrlExtraData((sheet_id << 1) | 1)))
    192        } else {
    193            Ok(ManuallyDrop::new(UrlExtraData(self.0)))
    194        }
    195    }
    196 }
    197 
    198 #[cfg(feature = "gecko")]
    199 impl UrlExtraData {
    200    /// Create a new UrlExtraData wrapping a pointer to the specified Gecko
    201    /// URLExtraData object.
    202    pub fn new(ptr: *mut structs::URLExtraData) -> UrlExtraData {
    203        unsafe {
    204            (*ptr).addref();
    205        }
    206        UrlExtraData(ptr as usize)
    207    }
    208 
    209    /// True if this URL scheme is chrome.
    210    #[inline]
    211    pub fn chrome_rules_enabled(&self) -> bool {
    212        self.as_ref().mChromeRulesEnabled
    213    }
    214 
    215    /// Create a reference to this `UrlExtraData` from a reference to pointer.
    216    ///
    217    /// The pointer must be valid and non null.
    218    ///
    219    /// This method doesn't touch refcount.
    220    #[inline]
    221    pub unsafe fn from_ptr_ref(ptr: &*mut structs::URLExtraData) -> &Self {
    222        mem::transmute(ptr)
    223    }
    224 
    225    /// Returns a pointer to the Gecko URLExtraData object.
    226    pub fn ptr(&self) -> *mut structs::URLExtraData {
    227        if self.0 & 1 == 0 {
    228            self.0 as *mut structs::URLExtraData
    229        } else {
    230            unsafe {
    231                let sheet_id = self.0 >> 1;
    232                structs::URLExtraData_sShared[sheet_id].mRawPtr
    233            }
    234        }
    235    }
    236 
    237    fn as_ref(&self) -> &structs::URLExtraData {
    238        unsafe { &*(self.ptr() as *const structs::URLExtraData) }
    239    }
    240 }
    241 
    242 #[cfg(feature = "gecko")]
    243 impl fmt::Debug for UrlExtraData {
    244    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
    245        macro_rules! define_debug_struct {
    246            ($struct_name:ident, $gecko_class:ident, $debug_fn:ident) => {
    247                struct $struct_name(*mut structs::$gecko_class);
    248                impl fmt::Debug for $struct_name {
    249                    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
    250                        use nsstring::nsCString;
    251                        let mut spec = nsCString::new();
    252                        unsafe {
    253                            bindings::$debug_fn(self.0, &mut spec);
    254                        }
    255                        spec.fmt(formatter)
    256                    }
    257                }
    258            };
    259        }
    260 
    261        define_debug_struct!(DebugURI, nsIURI, Gecko_nsIURI_Debug);
    262        define_debug_struct!(
    263            DebugReferrerInfo,
    264            nsIReferrerInfo,
    265            Gecko_nsIReferrerInfo_Debug
    266        );
    267 
    268        formatter
    269            .debug_struct("URLExtraData")
    270            .field("chrome_rules_enabled", &self.chrome_rules_enabled())
    271            .field("base", &DebugURI(self.as_ref().mBaseURI.raw()))
    272            .field(
    273                "referrer",
    274                &DebugReferrerInfo(self.as_ref().mReferrerInfo.raw()),
    275            )
    276            .finish()
    277    }
    278 }
    279 
    280 // XXX We probably need to figure out whether we should mark Eq here.
    281 // It is currently marked so because properties::UnparsedValue wants Eq.
    282 #[cfg(feature = "gecko")]
    283 impl Eq for UrlExtraData {}
    284 
    285 /// Serialize a page or style rule, starting with the opening brace.
    286 ///
    287 /// https://drafts.csswg.org/cssom/#serialize-a-css-rule CSSStyleRule
    288 ///
    289 /// This is not properly specified for page-rules, but we will apply the
    290 /// same process.
    291 fn style_or_page_rule_to_css(
    292    rules: Option<&Arc<Locked<CssRules>>>,
    293    block: &Locked<PropertyDeclarationBlock>,
    294    guard: &SharedRwLockReadGuard,
    295    dest: &mut CssStringWriter,
    296 ) -> fmt::Result {
    297    // Write the opening brace. The caller needs to serialize up to this point.
    298    dest.write_char('{')?;
    299 
    300    // Step 2
    301    let declaration_block = block.read_with(guard);
    302    let has_declarations = !declaration_block.declarations().is_empty();
    303 
    304    // Step 3
    305    if let Some(ref rules) = rules {
    306        let rules = rules.read_with(guard);
    307        // Step 6 (here because it's more convenient)
    308        if !rules.is_empty() {
    309            if has_declarations {
    310                dest.write_str("\n  ")?;
    311                declaration_block.to_css(dest)?;
    312            }
    313            return rules.to_css_block_without_opening(guard, dest);
    314        }
    315    }
    316 
    317    // Steps 4 & 5
    318    if has_declarations {
    319        dest.write_char(' ')?;
    320        declaration_block.to_css(dest)?;
    321    }
    322    dest.write_str(" }")
    323 }
    324 
    325 /// A CSS rule.
    326 ///
    327 /// TODO(emilio): Lots of spec links should be around.
    328 #[derive(Clone, Debug, ToShmem)]
    329 #[allow(missing_docs)]
    330 pub enum CssRule {
    331    Style(Arc<Locked<StyleRule>>),
    332    // No Charset here, CSSCharsetRule has been removed from CSSOM
    333    // https://drafts.csswg.org/cssom/#changes-from-5-december-2013
    334    Namespace(Arc<NamespaceRule>),
    335    Import(Arc<Locked<ImportRule>>),
    336    Media(Arc<MediaRule>),
    337    CustomMedia(Arc<CustomMediaRule>),
    338    Container(Arc<ContainerRule>),
    339    FontFace(Arc<Locked<FontFaceRule>>),
    340    FontFeatureValues(Arc<FontFeatureValuesRule>),
    341    FontPaletteValues(Arc<FontPaletteValuesRule>),
    342    CounterStyle(Arc<Locked<CounterStyleRule>>),
    343    Keyframes(Arc<Locked<KeyframesRule>>),
    344    Margin(Arc<MarginRule>),
    345    Supports(Arc<SupportsRule>),
    346    Page(Arc<Locked<PageRule>>),
    347    Property(Arc<PropertyRule>),
    348    Document(Arc<DocumentRule>),
    349    LayerBlock(Arc<LayerBlockRule>),
    350    LayerStatement(Arc<LayerStatementRule>),
    351    Scope(Arc<ScopeRule>),
    352    StartingStyle(Arc<StartingStyleRule>),
    353    PositionTry(Arc<Locked<PositionTryRule>>),
    354    NestedDeclarations(Arc<Locked<NestedDeclarationsRule>>),
    355 }
    356 
    357 impl CssRule {
    358    /// Measure heap usage.
    359    #[cfg(feature = "gecko")]
    360    fn size_of(&self, guard: &SharedRwLockReadGuard, ops: &mut MallocSizeOfOps) -> usize {
    361        match *self {
    362            // Not all fields are currently fully measured. Extra measurement
    363            // may be added later.
    364            CssRule::Namespace(_) => 0,
    365 
    366            // We don't need to measure ImportRule::stylesheet because we measure
    367            // it on the C++ side in the child list of the ServoStyleSheet.
    368            CssRule::Import(_) => 0,
    369 
    370            CssRule::Style(ref lock) => {
    371                lock.unconditional_shallow_size_of(ops) + lock.read_with(guard).size_of(guard, ops)
    372            },
    373            CssRule::Media(ref arc) => {
    374                arc.unconditional_shallow_size_of(ops) + arc.size_of(guard, ops)
    375            },
    376            CssRule::CustomMedia(ref arc) => {
    377                // Measurement of other fields might be added later.
    378                arc.unconditional_shallow_size_of(ops)
    379            },
    380            CssRule::Container(ref arc) => {
    381                arc.unconditional_shallow_size_of(ops) + arc.size_of(guard, ops)
    382            },
    383            CssRule::FontFace(_) => 0,
    384            CssRule::FontFeatureValues(_) => 0,
    385            CssRule::FontPaletteValues(_) => 0,
    386            CssRule::CounterStyle(_) => 0,
    387            CssRule::Keyframes(_) => 0,
    388            CssRule::Margin(ref arc) => {
    389                arc.unconditional_shallow_size_of(ops) + arc.size_of(guard, ops)
    390            },
    391            CssRule::Supports(ref arc) => {
    392                arc.unconditional_shallow_size_of(ops) + arc.size_of(guard, ops)
    393            },
    394            CssRule::Page(ref lock) => {
    395                lock.unconditional_shallow_size_of(ops) + lock.read_with(guard).size_of(guard, ops)
    396            },
    397            CssRule::Property(ref rule) => {
    398                rule.unconditional_shallow_size_of(ops) + rule.size_of(guard, ops)
    399            },
    400            CssRule::Document(ref arc) => {
    401                arc.unconditional_shallow_size_of(ops) + arc.size_of(guard, ops)
    402            },
    403            CssRule::StartingStyle(ref arc) => {
    404                arc.unconditional_shallow_size_of(ops) + arc.size_of(guard, ops)
    405            },
    406            // TODO(emilio): Add memory reporting for these rules.
    407            CssRule::LayerBlock(_) | CssRule::LayerStatement(_) => 0,
    408            CssRule::Scope(ref rule) => {
    409                rule.unconditional_shallow_size_of(ops) + rule.size_of(guard, ops)
    410            },
    411            CssRule::PositionTry(ref lock) => {
    412                lock.unconditional_shallow_size_of(ops) + lock.read_with(guard).size_of(guard, ops)
    413            },
    414            CssRule::NestedDeclarations(ref lock) => {
    415                lock.unconditional_shallow_size_of(ops) + lock.read_with(guard).size_of(guard, ops)
    416            },
    417        }
    418    }
    419 
    420    fn is_empty_nested_declarations(&self, guard: &SharedRwLockReadGuard) -> bool {
    421        match *self {
    422            CssRule::NestedDeclarations(ref lock) => {
    423                lock.read_with(guard).block.read_with(guard).is_empty()
    424            },
    425            _ => false,
    426        }
    427    }
    428 }
    429 
    430 // These aliases are required on Gecko side to avoid generating bindings for `Locked`.
    431 /// Alias for a locked style rule.
    432 pub type LockedStyleRule = Locked<StyleRule>;
    433 /// Alias for a locked import rule.
    434 pub type LockedImportRule = Locked<ImportRule>;
    435 /// Alias for a locked font-face rule.
    436 pub type LockedFontFaceRule = Locked<FontFaceRule>;
    437 /// Alias for a locked counter-style rule.
    438 pub type LockedCounterStyleRule = Locked<CounterStyleRule>;
    439 /// Alias for a locked keyframes rule.
    440 pub type LockedKeyframesRule = Locked<KeyframesRule>;
    441 /// Alias for a locked page rule.
    442 pub type LockedPageRule = Locked<PageRule>;
    443 /// Alias for a locked position-try rule.
    444 pub type LockedPositionTryRule = Locked<PositionTryRule>;
    445 /// Alias for a locked nested declarations rule.
    446 pub type LockedNestedDeclarationsRule = Locked<NestedDeclarationsRule>;
    447 
    448 /// A CSS rule reference. Should mirror `CssRule`.
    449 #[repr(C)]
    450 #[allow(missing_docs)]
    451 pub enum CssRuleRef<'a> {
    452    Style(&'a LockedStyleRule),
    453    Namespace(&'a NamespaceRule),
    454    Import(&'a LockedImportRule),
    455    Media(&'a MediaRule),
    456    CustomMedia(&'a CustomMediaRule),
    457    Container(&'a ContainerRule),
    458    FontFace(&'a LockedFontFaceRule),
    459    FontFeatureValues(&'a FontFeatureValuesRule),
    460    FontPaletteValues(&'a FontPaletteValuesRule),
    461    CounterStyle(&'a LockedCounterStyleRule),
    462    Keyframes(&'a LockedKeyframesRule),
    463    Margin(&'a MarginRule),
    464    Supports(&'a SupportsRule),
    465    Page(&'a LockedPageRule),
    466    Property(&'a PropertyRule),
    467    Document(&'a DocumentRule),
    468    LayerBlock(&'a LayerBlockRule),
    469    LayerStatement(&'a LayerStatementRule),
    470    Scope(&'a ScopeRule),
    471    StartingStyle(&'a StartingStyleRule),
    472    PositionTry(&'a LockedPositionTryRule),
    473    NestedDeclarations(&'a LockedNestedDeclarationsRule),
    474 }
    475 
    476 impl<'a> From<&'a CssRule> for CssRuleRef<'a> {
    477    fn from(value: &'a CssRule) -> Self {
    478        match value {
    479            CssRule::Style(r) => CssRuleRef::Style(r.as_ref()),
    480            CssRule::Namespace(r) => CssRuleRef::Namespace(r.as_ref()),
    481            CssRule::Import(r) => CssRuleRef::Import(r.as_ref()),
    482            CssRule::Media(r) => CssRuleRef::Media(r.as_ref()),
    483            CssRule::CustomMedia(r) => CssRuleRef::CustomMedia(r.as_ref()),
    484            CssRule::Container(r) => CssRuleRef::Container(r.as_ref()),
    485            CssRule::FontFace(r) => CssRuleRef::FontFace(r.as_ref()),
    486            CssRule::FontFeatureValues(r) => CssRuleRef::FontFeatureValues(r.as_ref()),
    487            CssRule::FontPaletteValues(r) => CssRuleRef::FontPaletteValues(r.as_ref()),
    488            CssRule::CounterStyle(r) => CssRuleRef::CounterStyle(r.as_ref()),
    489            CssRule::Keyframes(r) => CssRuleRef::Keyframes(r.as_ref()),
    490            CssRule::Margin(r) => CssRuleRef::Margin(r.as_ref()),
    491            CssRule::Supports(r) => CssRuleRef::Supports(r.as_ref()),
    492            CssRule::Page(r) => CssRuleRef::Page(r.as_ref()),
    493            CssRule::Property(r) => CssRuleRef::Property(r.as_ref()),
    494            CssRule::Document(r) => CssRuleRef::Document(r.as_ref()),
    495            CssRule::LayerBlock(r) => CssRuleRef::LayerBlock(r.as_ref()),
    496            CssRule::LayerStatement(r) => CssRuleRef::LayerStatement(r.as_ref()),
    497            CssRule::Scope(r) => CssRuleRef::Scope(r.as_ref()),
    498            CssRule::StartingStyle(r) => CssRuleRef::StartingStyle(r.as_ref()),
    499            CssRule::PositionTry(r) => CssRuleRef::PositionTry(r.as_ref()),
    500            CssRule::NestedDeclarations(r) => CssRuleRef::NestedDeclarations(r.as_ref()),
    501        }
    502    }
    503 }
    504 
    505 /// https://drafts.csswg.org/cssom-1/#dom-cssrule-type
    506 #[allow(missing_docs)]
    507 #[derive(Clone, Copy, Debug, Eq, FromPrimitive, PartialEq)]
    508 #[repr(u8)]
    509 pub enum CssRuleType {
    510    // https://drafts.csswg.org/cssom/#the-cssrule-interface
    511    Style = 1,
    512    // Charset = 2, // Historical
    513    Import = 3,
    514    Media = 4,
    515    FontFace = 5,
    516    Page = 6,
    517    // https://drafts.csswg.org/css-animations-1/#interface-cssrule-idl
    518    Keyframes = 7,
    519    Keyframe = 8,
    520    // https://drafts.csswg.org/cssom/#the-cssrule-interface
    521    Margin = 9,
    522    Namespace = 10,
    523    // https://drafts.csswg.org/css-counter-styles-3/#extentions-to-cssrule-interface
    524    CounterStyle = 11,
    525    // https://drafts.csswg.org/css-conditional-3/#extentions-to-cssrule-interface
    526    Supports = 12,
    527    // https://www.w3.org/TR/2012/WD-css3-conditional-20120911/#extentions-to-cssrule-interface
    528    Document = 13,
    529    // https://drafts.csswg.org/css-fonts/#om-fontfeaturevalues
    530    FontFeatureValues = 14,
    531    // After viewport, all rules should return 0 from the API, but we still need
    532    // a constant somewhere.
    533    LayerBlock = 16,
    534    LayerStatement = 17,
    535    Container = 18,
    536    FontPaletteValues = 19,
    537    // 20 is an arbitrary number to use for Property.
    538    Property = 20,
    539    Scope = 21,
    540    // https://drafts.csswg.org/css-transitions-2/#the-cssstartingstylerule-interface
    541    StartingStyle = 22,
    542    // https://drafts.csswg.org/css-anchor-position-1/#om-position-try
    543    PositionTry = 23,
    544    // https://drafts.csswg.org/css-nesting-1/#nested-declarations-rule
    545    NestedDeclarations = 24,
    546    CustomMedia = 25,
    547 }
    548 
    549 impl CssRuleType {
    550    /// Returns a bit that identifies this rule type.
    551    #[inline]
    552    pub const fn bit(self) -> u32 {
    553        1 << self as u32
    554    }
    555 }
    556 
    557 /// Set of rule types.
    558 #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
    559 pub struct CssRuleTypes(u32);
    560 
    561 impl From<CssRuleType> for CssRuleTypes {
    562    fn from(ty: CssRuleType) -> Self {
    563        Self(ty.bit())
    564    }
    565 }
    566 
    567 impl CssRuleTypes {
    568    /// Rules where !important declarations are forbidden.
    569    pub const IMPORTANT_FORBIDDEN: Self =
    570        Self(CssRuleType::PositionTry.bit() | CssRuleType::Keyframe.bit());
    571 
    572    /// Returns whether the rule is in the current set.
    573    #[inline]
    574    pub fn contains(self, ty: CssRuleType) -> bool {
    575        self.0 & ty.bit() != 0
    576    }
    577 
    578    /// Returns all the rules specified in the set.
    579    #[inline]
    580    pub fn bits(self) -> u32 {
    581        self.0
    582    }
    583 
    584    /// Creates a raw CssRuleTypes bitfield.
    585    #[inline]
    586    pub fn from_bits(bits: u32) -> Self {
    587        Self(bits)
    588    }
    589 
    590    /// Returns whether the rule set is empty.
    591    #[inline]
    592    pub fn is_empty(self) -> bool {
    593        self.0 == 0
    594    }
    595 
    596    /// Inserts a rule type into the set.
    597    #[inline]
    598    pub fn insert(&mut self, ty: CssRuleType) {
    599        self.0 |= ty.bit()
    600    }
    601 
    602    /// Returns whether any of the types intersect.
    603    #[inline]
    604    pub fn intersects(self, other: Self) -> bool {
    605        self.0 & other.0 != 0
    606    }
    607 }
    608 
    609 #[allow(missing_docs)]
    610 pub enum RulesMutateError {
    611    Syntax,
    612    IndexSize,
    613    HierarchyRequest,
    614    InvalidState,
    615 }
    616 
    617 impl CssRule {
    618    /// Returns the CSSOM rule type of this rule.
    619    pub fn rule_type(&self) -> CssRuleType {
    620        match *self {
    621            CssRule::Style(_) => CssRuleType::Style,
    622            CssRule::Import(_) => CssRuleType::Import,
    623            CssRule::Media(_) => CssRuleType::Media,
    624            CssRule::CustomMedia(_) => CssRuleType::CustomMedia,
    625            CssRule::FontFace(_) => CssRuleType::FontFace,
    626            CssRule::FontFeatureValues(_) => CssRuleType::FontFeatureValues,
    627            CssRule::FontPaletteValues(_) => CssRuleType::FontPaletteValues,
    628            CssRule::CounterStyle(_) => CssRuleType::CounterStyle,
    629            CssRule::Keyframes(_) => CssRuleType::Keyframes,
    630            CssRule::Margin(_) => CssRuleType::Margin,
    631            CssRule::Namespace(_) => CssRuleType::Namespace,
    632            CssRule::Supports(_) => CssRuleType::Supports,
    633            CssRule::Page(_) => CssRuleType::Page,
    634            CssRule::Property(_) => CssRuleType::Property,
    635            CssRule::Document(_) => CssRuleType::Document,
    636            CssRule::LayerBlock(_) => CssRuleType::LayerBlock,
    637            CssRule::LayerStatement(_) => CssRuleType::LayerStatement,
    638            CssRule::Container(_) => CssRuleType::Container,
    639            CssRule::Scope(_) => CssRuleType::Scope,
    640            CssRule::StartingStyle(_) => CssRuleType::StartingStyle,
    641            CssRule::PositionTry(_) => CssRuleType::PositionTry,
    642            CssRule::NestedDeclarations(_) => CssRuleType::NestedDeclarations,
    643        }
    644    }
    645 
    646    /// Parse a CSS rule.
    647    ///
    648    /// This mostly implements steps 3..7 of https://drafts.csswg.org/cssom/#insert-a-css-rule
    649    pub fn parse(
    650        css: &str,
    651        insert_rule_context: InsertRuleContext,
    652        parent_stylesheet_contents: &StylesheetContents,
    653        shared_lock: &SharedRwLock,
    654        loader: Option<&dyn StylesheetLoader>,
    655        allow_import_rules: AllowImportRules,
    656    ) -> Result<Self, RulesMutateError> {
    657        let url_data = &parent_stylesheet_contents.url_data;
    658        let namespaces = &parent_stylesheet_contents.namespaces;
    659        let mut context = ParserContext::new(
    660            parent_stylesheet_contents.origin,
    661            &url_data,
    662            None,
    663            ParsingMode::DEFAULT,
    664            parent_stylesheet_contents.quirks_mode,
    665            Cow::Borrowed(&*namespaces),
    666            None,
    667            None,
    668        );
    669        // Override the nesting context with existing data.
    670        context.nesting_context = NestingContext::new(
    671            insert_rule_context.containing_rule_types,
    672            insert_rule_context.parse_relative_rule_type,
    673        );
    674 
    675        let state = if !insert_rule_context.containing_rule_types.is_empty() {
    676            State::Body
    677        } else if insert_rule_context.index == 0 {
    678            State::Start
    679        } else {
    680            let index = insert_rule_context.index;
    681            insert_rule_context.max_rule_state_at_index(index - 1)
    682        };
    683 
    684        let mut input = ParserInput::new(css);
    685        let mut input = Parser::new(&mut input);
    686 
    687        // nested rules are in the body state
    688        let mut parser = TopLevelRuleParser {
    689            context,
    690            shared_lock: &shared_lock,
    691            loader,
    692            state,
    693            dom_error: None,
    694            insert_rule_context: Some(insert_rule_context),
    695            allow_import_rules,
    696            declaration_parser_state: Default::default(),
    697            first_declaration_block: Default::default(),
    698            wants_first_declaration_block: false,
    699            error_reporting_state: Default::default(),
    700            rules: Default::default(),
    701        };
    702 
    703        if input
    704            .try_parse(|input| parse_one_rule(input, &mut parser))
    705            .is_ok()
    706        {
    707            return Ok(parser.rules.pop().unwrap());
    708        }
    709 
    710        let error = parser.dom_error.take().unwrap_or(RulesMutateError::Syntax);
    711        // If new rule is a syntax error, and nested is set, perform the following substeps:
    712        if matches!(error, RulesMutateError::Syntax) && parser.can_parse_declarations() {
    713            let declarations = parse_property_declaration_list(&parser.context, &mut input, &[]);
    714            if !declarations.is_empty() {
    715                return Ok(CssRule::NestedDeclarations(Arc::new(
    716                    parser.shared_lock.wrap(NestedDeclarationsRule {
    717                        block: Arc::new(parser.shared_lock.wrap(declarations)),
    718                        source_location: input.current_source_location(),
    719                    }),
    720                )));
    721            }
    722        }
    723        Err(error)
    724    }
    725 }
    726 
    727 impl DeepCloneWithLock for CssRule {
    728    /// Deep clones this CssRule.
    729    fn deep_clone_with_lock(&self, lock: &SharedRwLock, guard: &SharedRwLockReadGuard) -> CssRule {
    730        match *self {
    731            CssRule::Namespace(ref arc) => CssRule::Namespace(arc.clone()),
    732            CssRule::Import(ref arc) => {
    733                let rule = arc.read_with(guard).deep_clone_with_lock(lock, guard);
    734                CssRule::Import(Arc::new(lock.wrap(rule)))
    735            },
    736            CssRule::Style(ref arc) => {
    737                let rule = arc.read_with(guard);
    738                CssRule::Style(Arc::new(lock.wrap(rule.deep_clone_with_lock(lock, guard))))
    739            },
    740            CssRule::Container(ref arc) => {
    741                CssRule::Container(Arc::new(arc.deep_clone_with_lock(lock, guard)))
    742            },
    743            CssRule::Media(ref arc) => {
    744                CssRule::Media(Arc::new(arc.deep_clone_with_lock(lock, guard)))
    745            },
    746            CssRule::CustomMedia(ref arc) => {
    747                CssRule::CustomMedia(Arc::new(arc.deep_clone_with_lock(lock, guard)))
    748            },
    749            CssRule::FontFace(ref arc) => {
    750                let rule = arc.read_with(guard);
    751                CssRule::FontFace(Arc::new(lock.wrap(rule.clone())))
    752            },
    753            CssRule::FontFeatureValues(ref arc) => CssRule::FontFeatureValues(arc.clone()),
    754            CssRule::FontPaletteValues(ref arc) => CssRule::FontPaletteValues(arc.clone()),
    755            CssRule::CounterStyle(ref arc) => {
    756                let rule = arc.read_with(guard);
    757                CssRule::CounterStyle(Arc::new(lock.wrap(rule.clone())))
    758            },
    759            CssRule::Keyframes(ref arc) => {
    760                let rule = arc.read_with(guard);
    761                CssRule::Keyframes(Arc::new(lock.wrap(rule.deep_clone_with_lock(lock, guard))))
    762            },
    763            CssRule::Margin(ref arc) => {
    764                CssRule::Margin(Arc::new(arc.deep_clone_with_lock(lock, guard)))
    765            },
    766            CssRule::Supports(ref arc) => {
    767                CssRule::Supports(Arc::new(arc.deep_clone_with_lock(lock, guard)))
    768            },
    769            CssRule::Page(ref arc) => {
    770                let rule = arc.read_with(guard);
    771                CssRule::Page(Arc::new(lock.wrap(rule.deep_clone_with_lock(lock, guard))))
    772            },
    773            CssRule::Property(ref arc) => {
    774                // @property rules are immutable, so we don't need any of the `Locked`
    775                // shenanigans, actually, and can just share the rule.
    776                CssRule::Property(arc.clone())
    777            },
    778            CssRule::Document(ref arc) => {
    779                CssRule::Document(Arc::new(arc.deep_clone_with_lock(lock, guard)))
    780            },
    781            CssRule::LayerStatement(ref arc) => CssRule::LayerStatement(arc.clone()),
    782            CssRule::LayerBlock(ref arc) => {
    783                CssRule::LayerBlock(Arc::new(arc.deep_clone_with_lock(lock, guard)))
    784            },
    785            CssRule::Scope(ref arc) => {
    786                CssRule::Scope(Arc::new(arc.deep_clone_with_lock(lock, guard)))
    787            },
    788            CssRule::StartingStyle(ref arc) => {
    789                CssRule::StartingStyle(Arc::new(arc.deep_clone_with_lock(lock, guard)))
    790            },
    791            CssRule::PositionTry(ref arc) => {
    792                let rule = arc.read_with(guard);
    793                CssRule::PositionTry(Arc::new(lock.wrap(rule.deep_clone_with_lock(lock, guard))))
    794            },
    795            CssRule::NestedDeclarations(ref arc) => {
    796                let decls = arc.read_with(guard);
    797                CssRule::NestedDeclarations(Arc::new(lock.wrap(decls.clone())))
    798            },
    799        }
    800    }
    801 }
    802 
    803 impl ToCssWithGuard for CssRule {
    804    // https://drafts.csswg.org/cssom/#serialize-a-css-rule
    805    fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
    806        match *self {
    807            CssRule::Namespace(ref rule) => rule.to_css(guard, dest),
    808            CssRule::Import(ref lock) => lock.read_with(guard).to_css(guard, dest),
    809            CssRule::Style(ref lock) => lock.read_with(guard).to_css(guard, dest),
    810            CssRule::FontFace(ref lock) => lock.read_with(guard).to_css(guard, dest),
    811            CssRule::FontFeatureValues(ref rule) => rule.to_css(guard, dest),
    812            CssRule::FontPaletteValues(ref rule) => rule.to_css(guard, dest),
    813            CssRule::CounterStyle(ref lock) => lock.read_with(guard).to_css(guard, dest),
    814            CssRule::Keyframes(ref lock) => lock.read_with(guard).to_css(guard, dest),
    815            CssRule::Margin(ref rule) => rule.to_css(guard, dest),
    816            CssRule::Media(ref rule) => rule.to_css(guard, dest),
    817            CssRule::CustomMedia(ref rule) => rule.to_css(guard, dest),
    818            CssRule::Supports(ref rule) => rule.to_css(guard, dest),
    819            CssRule::Page(ref lock) => lock.read_with(guard).to_css(guard, dest),
    820            CssRule::Property(ref rule) => rule.to_css(guard, dest),
    821            CssRule::Document(ref rule) => rule.to_css(guard, dest),
    822            CssRule::LayerBlock(ref rule) => rule.to_css(guard, dest),
    823            CssRule::LayerStatement(ref rule) => rule.to_css(guard, dest),
    824            CssRule::Container(ref rule) => rule.to_css(guard, dest),
    825            CssRule::Scope(ref rule) => rule.to_css(guard, dest),
    826            CssRule::StartingStyle(ref rule) => rule.to_css(guard, dest),
    827            CssRule::PositionTry(ref lock) => lock.read_with(guard).to_css(guard, dest),
    828            CssRule::NestedDeclarations(ref lock) => lock.read_with(guard).to_css(guard, dest),
    829        }
    830    }
    831 }