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 }