/* This Source Code Form is subject to the terms of the Mozilla Public *License,v.2.0.IfacopyoftheMPLwasnotdistributedwiththis
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
usecrate::context::QuirksMode; usecrate::derives::*; usecrate::device::Device; usecrate::error_reporting::{ContextualParseError, ParseErrorReporter}; usecrate::media_queries::MediaList; usecrate::parser::ParserContext; usecrate::shared_lock::{DeepCloneWithLock, Locked}; usecrate::shared_lock::{SharedRwLock, SharedRwLockReadGuard}; usecrate::stylesheets::loader::StylesheetLoader; usecrate::stylesheets::rule_parser::{State, TopLevelRuleParser}; usecrate::stylesheets::rules_iterator::{EffectiveRules, EffectiveRulesIterator}; usecrate::stylesheets::rules_iterator::{NestedRuleIterationCondition, RulesIterator}; usecrate::stylesheets::{
CssRule, CssRules, CustomMediaEvaluator, CustomMediaMap, Origin, UrlExtraData,
}; usecrate::use_counters::UseCounters; usecrate::{Namespace, Prefix}; use cssparser::{Parser, ParserInput, StyleSheetParser}; #[cfg(feature = "gecko")] use malloc_size_of::{MallocSizeOfOps, MallocUnconditionalShallowSizeOf}; use rustc_hash::FxHashMap; use servo_arc::Arc; use std::ops::Deref; use std::sync::atomic::{AtomicBool, Ordering}; use style_traits::ParsingMode;
usesuper::scope_rule::ImplicitScopeRoot;
/// A set of namespaces applying to a given stylesheet. /// /// The namespace id is used in gecko #[derive(Clone, Debug, Default, MallocSizeOf)] #[allow(missing_docs)] pubstruct 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)] pubstruct 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: UrlExtraData, /// The namespaces that apply to this stylesheet. pub namespaces: Namespaces, /// The quirks mode of this stylesheet. pub quirks_mode: QuirksMode, /// This stylesheet's source map URL. pub source_map_url: Option<String>, /// This stylesheet's source URL. pub source_url: Option<String>, /// The use counters of the original stylesheet. pub use_counters: UseCounters,
/// 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. pubfn 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,
allow_import_rules: AllowImportRules,
sanitization_data: Option<&mut SanitizationData>,
) -> Arc<Self> { let use_counters = UseCounters::default(); let (namespaces, rules, source_map_url, source_url) = Stylesheet::parse_rules(
css,
&url_data,
origin,
&shared_lock,
stylesheet_loader,
error_reporter,
quirks_mode,
Some(&use_counters),
allow_import_rules,
sanitization_data,
);
/// 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. pubfn from_shared_data(
rules: Arc<Locked<CssRules>>,
origin: Origin,
url_data: UrlExtraData,
quirks_mode: QuirksMode,
) -> Arc<Self> {
debug_assert!(rules.is_static());
Arc::new(Self {
rules,
origin,
url_data,
namespaces: Namespaces::default(),
quirks_mode,
source_map_url: None,
source_url: None,
use_counters: UseCounters::default(),
_forbid_construction: (),
})
}
/// Returns a reference to the list of rules. #[inline] pubfn rules<'a, 'b: 'a>(&'a self, guard: &'b SharedRwLockReadGuard) -> &'a [CssRule] {
&self.rules.read_with(guard).0
}
/// Measure heap usage. #[cfg(feature = "gecko")] pubfn size_of(&self, guard: &SharedRwLockReadGuard, ops: &mut MallocSizeOfOps) -> usize { ifself.rules.is_static() { return0;
} // Measurement of other fields may be added later. self.rules.unconditional_shallow_size_of(ops)
+ self.rules.read_with(guard).size_of(guard, ops)
}
/// Return an iterator over the effective rules within the style-sheet, as /// according to the supplied `Device`. #[inline] pubfn effective_rules<'a, 'b, CMM: Deref<Target = CustomMediaMap>>(
&'a self,
device: &'a Device,
custom_media: CMM,
guard: &'a SharedRwLockReadGuard<'b>,
) -> EffectiveRulesIterator<'a, 'b, CMM> { self.iter_rules::<EffectiveRules, CMM>(device, custom_media, guard)
}
/// Perform a deep clone, of this stylesheet, with an explicit URL data if needed. pubfn deep_clone(
&self,
lock: &SharedRwLock,
url_data: Option<&UrlExtraData>,
guard: &SharedRwLockReadGuard,
) -> Arc<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);
let url_data = url_data.cloned().unwrap_or_else(|| self.url_data.clone());
/// The structure servo uses to represent a stylesheet. #[derive(Debug)] pubstruct Stylesheet { /// The contents of this stylesheet. pub contents: Locked<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,
}
/// A trait to represent a given stylesheet in a document. pubtrait 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 contents of the stylesheet. fn contents<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> &'</span>a StylesheetContents;
/// Returns whether the style-sheet applies for the current device. fn is_effective_for_device(
&self,
device: &Device,
custom_media: &CustomMediaMap,
guard: &SharedRwLockReadGuard,
) -> bool { let media = matchself.media(guard) {
Some(m) => m,
None => returntrue,
};
media.evaluate(
device, self.contents(guard).quirks_mode,
&mut CustomMediaEvaluator::new(custom_media, guard),
)
}
/// Return the implicit scope root for this stylesheet, if one exists. fn implicit_scope_root(&self) -> Option<ImplicitScopeRoot>;
}
/// 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))] pubstruct DocumentStyleSheet( #[cfg_attr(feature = "servo", ignore_malloc_size_of = "Arc")] pub Arc<Stylesheet>,
);
/// The kind of sanitization to use when parsing a stylesheet. #[repr(u8)] #[derive(Clone, Copy, Debug, PartialEq)] pubenum 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)] pubenum AllowImportRules { /// @import rules will be parsed.
Yes, /// @import rules will not be parsed.
No,
}
impl SanitizationKind { fn allows(self, rule: &CssRule, guard: &SharedRwLockReadGuard) -> bool { if !self.allows_self(rule) { returnfalse;
} for child in rule.children(guard) { if !self.allows(child, guard) { returnfalse;
}
} true
}
fn allows_self(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::CustomMedia(..) |
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(..) | // TODO(dshin): Same comment as Layer applies - shouldn't give away // something like display size - erring on the side of "safe" for now.
CssRule::Scope(..) |
CssRule::StartingStyle(..) |
CssRule::AppearanceBase(..) => false,
/// A struct to hold the data relevant to style sheet sanitization. #[derive(Debug)] pubstruct SanitizationData {
kind: SanitizationKind,
output: String,
}
impl SanitizationData { /// Create a new input for sanitization. #[inline] pubfn new(kind: SanitizationKind) -> Option<Self> { if matches!(kind, SanitizationKind::None) { return None;
}
Some(Self {
kind,
output: String::new(),
})
}
/// Take the sanitized output. #[inline] pubfn take(self) -> String { self.output
}
}
/// Returns whether the stylesheet has been explicitly disabled through the /// CSSOM. pubfn 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. pubfn 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 = lock.wrap( self.contents
.read_with(&guard)
.deep_clone(&lock, None, &guard),
);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.