/* 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/. */
//! Style sheets and their CSS rules.
pubmod container_rule; mod counter_style_rule; mod document_rule; mod font_face_rule; pubmod font_feature_values_rule; pubmod font_palette_values_rule; pubmod import_rule; pubmod keyframes_rule; pubmod layer_rule; mod loader; mod margin_rule; mod media_rule; mod namespace_rule; mod nested_declarations_rule; pubmod origin; mod page_rule; pubmod position_try_rule; mod property_rule; mod rule_list; mod rule_parser; mod rules_iterator; pubmod scope_rule; mod starting_style_rule; mod style_rule; mod stylesheet; pubmod supports_rule;
#[cfg(feature = "gecko")] usecrate::gecko_bindings::sugar::refptr::RefCounted; #[cfg(feature = "gecko")] usecrate::gecko_bindings::{bindings, structs}; usecrate::parser::{NestingContext, ParserContext}; usecrate::properties::{parse_property_declaration_list, PropertyDeclarationBlock}; usecrate::shared_lock::{DeepCloneWithLock, Locked}; usecrate::shared_lock::{SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard}; usecrate::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::{self, Write}; #[cfg(feature = "gecko")] use std::mem::{self, ManuallyDrop}; use style_traits::ParsingMode; use to_shmem::{SharedMemoryBuilder, ToShmem};
/// The CORS mode used for a CSS load. #[repr(u8)] #[derive(Clone, Copy, Debug, Eq, PartialEq, ToShmem)] pubenum 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")] // Although deriving MallocSizeOf means it always returns 0, that is fine because UrlExtraData // objects are reference-counted. #[derive(MallocSizeOf, PartialEq)] #[repr(C)] pubstruct UrlExtraData(usize);
/// Extra data that the backend may need to resolve url values. #[cfg(feature = "servo")] #[derive(Clone, Debug, Eq, PartialEq)] pubstruct UrlExtraData(pub Arc<::url::Url>);
#[cfg(feature = "servo")] impl UrlExtraData { /// True if this URL scheme is chrome. pubfn chrome_rules_enabled(&self) -> bool { self.0.scheme() == "chrome"
}
/// Get the interior Url as a string. pubfn as_str(&self) -> &str { self.0.as_str()
}
}
#[cfg(feature = "gecko")] impl Drop for UrlExtraData { fn drop(&mutself) { // No need to release when we have an index into URLExtraData_sShared. ifself.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> { ifself.0 & 1 == 0 { let shared_extra_datas = unsafe {
std::ptr::addr_of!(structs::URLExtraData_sShared)
.as_ref()
.unwrap()
}; 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. pubfn new(ptr: *mut structs::URLExtraData) -> UrlExtraData { unsafe {
(*ptr).addref();
}
UrlExtraData(ptr as usize)
}
/// True if this URL scheme is chrome. #[inline] pubfn 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] pubunsafefn from_ptr_ref(ptr: &*mut structs::URLExtraData) -> &n style='color:red'>Self {
mem::transmute(ptr)
}
/// Returns a pointer to the Gecko URLExtraData object. pubfn ptr(&self) -> *mut structs::URLExtraData { ifself.0 & 1 == 0 { self.0as *mut structs::URLExtraData
} else { unsafe { let sheet_id = self.0 >> 1;
structs::URLExtraData_sShared[sheet_id].mRawPtr
}
}
}
// 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 {}
/// Serialize a page or style rule, starting with the opening brace. /// /// https://drafts.csswg.org/cssom/#serialize-a-css-rule CSSStyleRule /// /// This is not properly specified for page-rules, but we will apply the /// same process. fn style_or_page_rule_to_css(
rules: Option<&Arc<Locked<CssRules>>>,
block: &Locked<PropertyDeclarationBlock>,
guard: &SharedRwLockReadGuard,
dest: &mut CssStringWriter,
) -> fmt::Result { // Write the opening brace. The caller needs to serialize up to this point.
dest.write_char('{')?;
// Step 2 let declaration_block = block.read_with(guard); let has_declarations = !declaration_block.declarations().is_empty();
// Step 3 iflet Some(ref rules) = 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);
}
}
/// A CSS rule. /// /// TODO(emilio): Lots of spec links should be around. #[derive(Clone, Debug, ToShmem)] #[allow(missing_docs)] pubenum CssRule {
Style(Arc<Locked<StyleRule>>), // 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>>),
Media(Arc<MediaRule>),
Container(Arc<ContainerRule>),
FontFace(Arc<Locked<FontFaceRule>>),
FontFeatureValues(Arc<FontFeatureValuesRule>),
FontPaletteValues(Arc<FontPaletteValuesRule>),
CounterStyle(Arc<Locked<CounterStyleRule>>),
Keyframes(Arc<Locked<KeyframesRule>>),
Margin(Arc<MarginRule>),
Supports(Arc<SupportsRule>),
Page(Arc<Locked<PageRule>>),
Property(Arc<PropertyRule>),
Document(Arc<DocumentRule>),
LayerBlock(Arc<LayerBlockRule>),
LayerStatement(Arc<LayerStatementRule>),
Scope(Arc<ScopeRule>),
StartingStyle(Arc<StartingStyleRule>),
PositionTry(Arc<Locked<PositionTryRule>>),
NestedDeclarations(Arc<Locked<NestedDeclarationsRule>>),
}
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,
/// Parse a CSS rule. /// /// This mostly implements steps 3..7 of https://drafts.csswg.org/cssom/#insert-a-css-rule pubfn parse(
css: &str,
insert_rule_context: InsertRuleContext,
parent_stylesheet_contents: &StylesheetContents,
shared_lock: &SharedRwLock,
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(); letmut context = ParserContext::new(
parent_stylesheet_contents.origin,
&url_data,
None,
ParsingMode::DEFAULT,
parent_stylesheet_contents.quirks_mode,
Cow::Borrowed(&*namespaces),
None,
None,
); // Override the nesting context with existing data.
context.nesting_context = NestingContext::new(
insert_rule_context.containing_rule_types,
insert_rule_context.parse_relative_rule_type,
);
let state = if !insert_rule_context.containing_rule_types.is_empty() {
State::Body
} elseif insert_rule_context.index == 0 {
State::Start
} else { let index = insert_rule_context.index;
insert_rule_context.max_rule_state_at_index(index - 1)
};
// nested rules are in the body state letmut 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(),
first_declaration_block: Default::default(),
wants_first_declaration_block: false,
error_reporting_state: Default::default(),
rules: Default::default(),
};
if input.try_parse(|input| parse_one_rule(input, &mut parser)).is_ok() { return Ok(parser.rules.pop().unwrap());
}
let error = parser.dom_error.take().unwrap_or(RulesMutateError::Syntax); // If new rule is a syntax error, and nested is set, perform the following substeps: if matches!(error, RulesMutateError::Syntax) && parser.can_parse_declarations() { let declarations = parse_property_declaration_list(&parser.context, &mut input, &[]); if !declarations.is_empty() { return Ok(CssRule::NestedDeclarations(Arc::new(parser.shared_lock.wrap(NestedDeclarationsRule {
block: Arc::new(parser.shared_lock.wrap(declarations)),
source_location: input.current_source_location(),
}))));
}
}
Err(error)
}
}
impl DeepCloneWithLock for CssRule { /// Deep clones this CssRule. fn deep_clone_with_lock(&self, lock: &SharedRwLock, guard: &SharedRwLockReadGuard) -> 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);
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))))
},
CssRule::Container(ref arc) => {
CssRule::Container(Arc::new(arc.deep_clone_with_lock(lock, guard)))
},
CssRule::Media(ref arc) => {
CssRule::Media(Arc::new(arc.deep_clone_with_lock(lock, guard)))
},
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))))
},
CssRule::Margin(ref arc) => {
CssRule::Margin(Arc::new(arc.deep_clone_with_lock(lock, guard)))
},
CssRule::Supports(ref arc) => {
CssRule::Supports(Arc::new(arc.deep_clone_with_lock(lock, guard)))
},
CssRule::Page(ref arc) => { let rule = arc.read_with(guard);
CssRule::Page(Arc::new(lock.wrap(rule.deep_clone_with_lock(lock, guard))))
},
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)))
},
CssRule::LayerStatement(ref arc) => CssRule::LayerStatement(arc.clone()),
CssRule::LayerBlock(ref arc) => {
CssRule::LayerBlock(Arc::new(arc.deep_clone_with_lock(lock, guard)))
},
CssRule::Scope(ref arc) => {
CssRule::Scope(Arc::new(arc.deep_clone_with_lock(lock, guard)))
},
CssRule::StartingStyle(ref arc) => {
CssRule::StartingStyle(Arc::new(arc.deep_clone_with_lock(lock, guard)))
},
CssRule::PositionTry(ref arc) => { let rule = arc.read_with(guard);
CssRule::PositionTry(Arc::new(lock.wrap(rule.deep_clone_with_lock(lock, guard))))
},
CssRule::NestedDeclarations(ref arc) => { let decls = arc.read_with(guard);
CssRule::NestedDeclarations(Arc::new(lock.wrap(decls.clone())))
},
}
}
}
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.