mirror of
https://github.com/servo/servo.git
synced 2025-08-04 21:20:23 +01:00
style: Add a struct to represent import rules, and parse them correctly.
This commit is contained in:
parent
e5d783c454
commit
444fef164e
3 changed files with 103 additions and 7 deletions
|
@ -26,6 +26,7 @@ use std::sync::Arc;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use style_traits::ToCss;
|
use style_traits::ToCss;
|
||||||
use stylist::FnvHashMap;
|
use stylist::FnvHashMap;
|
||||||
|
use values::specified::url::SpecifiedUrl;
|
||||||
use viewport::ViewportRule;
|
use viewport::ViewportRule;
|
||||||
|
|
||||||
|
|
||||||
|
@ -79,7 +80,8 @@ impl CssRules {
|
||||||
fn only_ns_or_import(&self) -> bool {
|
fn only_ns_or_import(&self) -> bool {
|
||||||
self.0.iter().all(|r| {
|
self.0.iter().all(|r| {
|
||||||
match *r {
|
match *r {
|
||||||
CssRule::Namespace(..) /* | CssRule::Import(..) */ => true,
|
CssRule::Namespace(..) |
|
||||||
|
CssRule::Import(..) => true,
|
||||||
_ => false
|
_ => false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -180,6 +182,7 @@ pub enum CssRule {
|
||||||
// https://drafts.csswg.org/cssom/#changes-from-5-december-2013
|
// https://drafts.csswg.org/cssom/#changes-from-5-december-2013
|
||||||
|
|
||||||
Namespace(Arc<RwLock<NamespaceRule>>),
|
Namespace(Arc<RwLock<NamespaceRule>>),
|
||||||
|
Import(Arc<RwLock<ImportRule>>),
|
||||||
Style(Arc<RwLock<StyleRule>>),
|
Style(Arc<RwLock<StyleRule>>),
|
||||||
Media(Arc<RwLock<MediaRule>>),
|
Media(Arc<RwLock<MediaRule>>),
|
||||||
FontFace(Arc<RwLock<FontFaceRule>>),
|
FontFace(Arc<RwLock<FontFaceRule>>),
|
||||||
|
@ -235,6 +238,7 @@ impl CssRule {
|
||||||
pub fn rule_type(&self) -> CssRuleType {
|
pub fn rule_type(&self) -> CssRuleType {
|
||||||
match *self {
|
match *self {
|
||||||
CssRule::Style(_) => CssRuleType::Style,
|
CssRule::Style(_) => CssRuleType::Style,
|
||||||
|
CssRule::Import(_) => CssRuleType::Import,
|
||||||
CssRule::Media(_) => CssRuleType::Media,
|
CssRule::Media(_) => CssRuleType::Media,
|
||||||
CssRule::FontFace(_) => CssRuleType::FontFace,
|
CssRule::FontFace(_) => CssRuleType::FontFace,
|
||||||
CssRule::Keyframes(_) => CssRuleType::Keyframes,
|
CssRule::Keyframes(_) => CssRuleType::Keyframes,
|
||||||
|
@ -246,7 +250,7 @@ impl CssRule {
|
||||||
fn rule_state(&self) -> State {
|
fn rule_state(&self) -> State {
|
||||||
match *self {
|
match *self {
|
||||||
// CssRule::Charset(..) => State::Start,
|
// CssRule::Charset(..) => State::Start,
|
||||||
// CssRule::Import(..) => State::Imports,
|
CssRule::Import(..) => State::Imports,
|
||||||
CssRule::Namespace(..) => State::Namespaces,
|
CssRule::Namespace(..) => State::Namespaces,
|
||||||
_ => State::Body,
|
_ => State::Body,
|
||||||
}
|
}
|
||||||
|
@ -254,10 +258,19 @@ impl CssRule {
|
||||||
|
|
||||||
/// Call `f` with the slice of rules directly contained inside this rule.
|
/// Call `f` with the slice of rules directly contained inside this rule.
|
||||||
///
|
///
|
||||||
/// Note that only some types of rules can contain rules. An empty slice is used for others.
|
/// Note that only some types of rules can contain rules. An empty slice is
|
||||||
|
/// used for others.
|
||||||
pub fn with_nested_rules_and_mq<F, R>(&self, mut f: F) -> R
|
pub fn with_nested_rules_and_mq<F, R>(&self, mut f: F) -> R
|
||||||
where F: FnMut(&[CssRule], Option<&MediaList>) -> R {
|
where F: FnMut(&[CssRule], Option<&MediaList>) -> R {
|
||||||
match *self {
|
match *self {
|
||||||
|
CssRule::Import(ref lock) => {
|
||||||
|
let rule = lock.read();
|
||||||
|
let media = rule.stylesheet.media.read();
|
||||||
|
let rules = rule.stylesheet.rules.read();
|
||||||
|
// FIXME(emilio): Include the nested rules if the stylesheet is
|
||||||
|
// loaded.
|
||||||
|
f(&rules.0, Some(&media))
|
||||||
|
}
|
||||||
CssRule::Namespace(_) |
|
CssRule::Namespace(_) |
|
||||||
CssRule::Style(_) |
|
CssRule::Style(_) |
|
||||||
CssRule::FontFace(_) |
|
CssRule::FontFace(_) |
|
||||||
|
@ -315,6 +328,7 @@ impl ToCss for CssRule {
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||||
match *self {
|
match *self {
|
||||||
CssRule::Namespace(ref lock) => lock.read().to_css(dest),
|
CssRule::Namespace(ref lock) => lock.read().to_css(dest),
|
||||||
|
CssRule::Import(ref lock) => lock.read().to_css(dest),
|
||||||
CssRule::Style(ref lock) => lock.read().to_css(dest),
|
CssRule::Style(ref lock) => lock.read().to_css(dest),
|
||||||
CssRule::FontFace(ref lock) => lock.read().to_css(dest),
|
CssRule::FontFace(ref lock) => lock.read().to_css(dest),
|
||||||
CssRule::Viewport(ref lock) => lock.read().to_css(dest),
|
CssRule::Viewport(ref lock) => lock.read().to_css(dest),
|
||||||
|
@ -346,6 +360,34 @@ impl ToCss for NamespaceRule {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// The [`@import`][import] at-rule.
|
||||||
|
///
|
||||||
|
/// [import]: https://drafts.csswg.org/css-cascade-3/#at-import
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ImportRule {
|
||||||
|
pub url: SpecifiedUrl,
|
||||||
|
|
||||||
|
/// The stylesheet is always present.
|
||||||
|
///
|
||||||
|
/// It contains an empty list of rules and namespace set that is updated
|
||||||
|
/// when it loads.
|
||||||
|
pub stylesheet: Arc<Stylesheet>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToCss for ImportRule {
|
||||||
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||||
|
try!(dest.write_str("@import "));
|
||||||
|
try!(self.url.to_css(dest));
|
||||||
|
let media = self.stylesheet.media.read();
|
||||||
|
if !media.is_empty() {
|
||||||
|
try!(dest.write_str(" "));
|
||||||
|
try!(media.to_css(dest));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct KeyframesRule {
|
pub struct KeyframesRule {
|
||||||
pub name: Atom,
|
pub name: Atom,
|
||||||
|
@ -612,8 +654,32 @@ impl<'a> AtRuleParser for TopLevelRuleParser<'a> {
|
||||||
"import" => {
|
"import" => {
|
||||||
if self.state.get() <= State::Imports {
|
if self.state.get() <= State::Imports {
|
||||||
self.state.set(State::Imports);
|
self.state.set(State::Imports);
|
||||||
// TODO: support @import
|
let url = try!(input.expect_url_or_string());
|
||||||
return Err(()) // "@import is not supported yet"
|
let url =
|
||||||
|
try!(SpecifiedUrl::parse_from_string(url,
|
||||||
|
&self.context));
|
||||||
|
|
||||||
|
let media =
|
||||||
|
Arc::new(RwLock::new(parse_media_query_list(input)));
|
||||||
|
|
||||||
|
let is_valid_url = url.url().is_some();
|
||||||
|
|
||||||
|
let import_rule = Arc::new(RwLock::new(
|
||||||
|
ImportRule {
|
||||||
|
url: url,
|
||||||
|
stylesheet: Arc::new(Stylesheet {
|
||||||
|
rules: Arc::new(RwLock::new(CssRules(vec![]))),
|
||||||
|
media: media,
|
||||||
|
origin: self.context.stylesheet_origin,
|
||||||
|
base_url: self.context.base_url.clone(),
|
||||||
|
namespaces: RwLock::new(Namespaces::default()),
|
||||||
|
dirty_on_viewport_size_change: AtomicBool::new(false),
|
||||||
|
disabled: AtomicBool::new(false),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
return Ok(AtRuleType::WithoutBlock(CssRule::Import(import_rule)))
|
||||||
} else {
|
} else {
|
||||||
self.state.set(State::Invalid);
|
self.state.set(State::Invalid);
|
||||||
return Err(()) // "@import must be before any rule but @charset"
|
return Err(()) // "@import must be before any rule but @charset"
|
||||||
|
|
|
@ -165,6 +165,25 @@ impl Stylist {
|
||||||
self.add_stylesheet(stylesheet);
|
self.add_stylesheet(stylesheet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debug!("Stylist stats:");
|
||||||
|
debug!(" - Got {} sibling-affecting selectors",
|
||||||
|
self.sibling_affecting_selectors.len());
|
||||||
|
debug!(" - Got {} non-common-style-attribute-affecting selectors",
|
||||||
|
self.non_common_style_affecting_attributes_selectors.len());
|
||||||
|
debug!(" - Got {} deps for style-hint calculation",
|
||||||
|
self.state_deps.len());
|
||||||
|
|
||||||
|
SelectorImpl::each_precomputed_pseudo_element(|pseudo| {
|
||||||
|
// TODO: Consider not doing this and just getting the rules on the
|
||||||
|
// fly. It should be a bit slower, but we'd take rid of the
|
||||||
|
// extra field, and avoid this precomputation entirely.
|
||||||
|
if let Some(map) = self.pseudos_map.remove(&pseudo) {
|
||||||
|
let mut declarations = vec![];
|
||||||
|
map.user_agent.get_universal_rules(&mut declarations);
|
||||||
|
self.precomputed_pseudo_element_decls.insert(pseudo, declarations);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
self.is_device_dirty = false;
|
self.is_device_dirty = false;
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -211,6 +230,10 @@ impl Stylist {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
CssRule::Import(ref import) => {
|
||||||
|
let import = import.read();
|
||||||
|
self.add_stylesheet(&import.stylesheet)
|
||||||
|
}
|
||||||
CssRule::Keyframes(ref keyframes_rule) => {
|
CssRule::Keyframes(ref keyframes_rule) => {
|
||||||
let keyframes_rule = keyframes_rule.read();
|
let keyframes_rule = keyframes_rule.read();
|
||||||
debug!("Found valid keyframes rule: {:?}", *keyframes_rule);
|
debug!("Found valid keyframes rule: {:?}", *keyframes_rule);
|
||||||
|
@ -250,6 +273,7 @@ impl Stylist {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Computes the style for a given "precomputed" pseudo-element, taking the
|
/// Computes the style for a given "precomputed" pseudo-element, taking the
|
||||||
/// universal rules and applying them.
|
/// universal rules and applying them.
|
||||||
///
|
///
|
||||||
|
|
|
@ -11,6 +11,7 @@ use parser::{Parse, ParserContext};
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
use parser::ParserContextExtraData;
|
use parser::ParserContextExtraData;
|
||||||
use servo_url::ServoUrl;
|
use servo_url::ServoUrl;
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::fmt::{self, Write};
|
use std::fmt::{self, Write};
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
@ -76,7 +77,14 @@ pub struct SpecifiedUrl {
|
||||||
impl Parse for SpecifiedUrl {
|
impl Parse for SpecifiedUrl {
|
||||||
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
|
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
|
||||||
let url = try!(input.expect_url());
|
let url = try!(input.expect_url());
|
||||||
|
Self::parse_from_string(url, context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SpecifiedUrl {
|
||||||
|
pub fn parse_from_string<'a>(url: Cow<'a, str>,
|
||||||
|
context: &ParserContext)
|
||||||
|
-> Result<Self, ()> {
|
||||||
let extra_data = match UrlExtraData::make_from(context) {
|
let extra_data = match UrlExtraData::make_from(context) {
|
||||||
Some(extra_data) => extra_data,
|
Some(extra_data) => extra_data,
|
||||||
None => {
|
None => {
|
||||||
|
@ -96,9 +104,7 @@ impl Parse for SpecifiedUrl {
|
||||||
extra_data: extra_data,
|
extra_data: extra_data,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl SpecifiedUrl {
|
|
||||||
pub fn extra_data(&self) -> &UrlExtraData {
|
pub fn extra_data(&self) -> &UrlExtraData {
|
||||||
&self.extra_data
|
&self.extra_data
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue